From e912fcde7b99b5a09513bf8a0acb4d6c5db06e42 Mon Sep 17 00:00:00 2001 From: Richard Grenville Date: Mon, 19 Nov 2012 09:46:07 +0800 Subject: [PATCH] Feature #51: Re-initialize when SIGUSR1 is received - Create a session_t structure, to get rid of most global variables and let information pass in/out mostly through parameters. Huge changes, so bugs may very well appear. I'm worried about resource leakages, in particular. - Add gcc attributes on various functions. - Add Doxygen configuration. - Replace much Xlib Bool with C99 bool. - Add and adjust some comments. - Drop unused parameters from some functions. - Cache default Visual and Depth, mainly to shorten code. - Rename some types, variables, and functions. - Add win_ev_stop() and set_ignore_next() for convenience. - Modify wid_get_prop_wintype() and wid_get_opacity_prop() to use wid_get_prop(). - Rename --respect-attr-shadow to --respect-prop-shadow. - Fix a memory leak in --respect-prop-shadow. - Many other small changes. --- .gitignore | 3 +- Doxyfile | 1808 ++++++++++++++++++++++++++++++ src/compton.c | 2924 ++++++++++++++++++++++++++----------------------- src/compton.h | 1093 +++++++++++------- 4 files changed, 4065 insertions(+), 1763 deletions(-) create mode 100644 Doxyfile diff --git a/.gitignore b/.gitignore index e67a0b30..475cacb0 100644 --- a/.gitignore +++ b/.gitignore @@ -34,7 +34,8 @@ install_manifest.txt # Misc files core -oprofile_data +oprofile_data/ compton.plist callgrind.out.* man/*.html +doxygen/ diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 00000000..eddba846 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,1808 @@ +# Doxyfile 1.8.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "compton" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doxygen + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter and setter methods for a property. Setting this option to YES (the default) will make doxygen replace the get and set methods by a property in the documentation. This will only work if the methods are indeed getting or setting a simple type. If this is not the case, or you want to show the methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = src + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = __attribute__(x)= + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/src/compton.c b/src/compton.c index 080fd0a8..e10c4c2d 100644 --- a/src/compton.c +++ b/src/compton.c @@ -10,16 +10,18 @@ #include "compton.h" -#define MSTR_(s) #s -#define MSTR(s) MSTR_(s) +// === Macros === + +// #define MSTR_(s) #s +// #define MSTR(s) MSTR_(s) // Use #s here to prevent macro expansion +/// Macro used for shortening some debugging code. #define CASESTRRET(s) case s: return #s -/** - * Shared - */ +// === Global constants === +/// Name strings for window types. const char *WINTYPES[NUM_WINTYPES] = { "unknown", "desktop", @@ -38,207 +40,22 @@ const char *WINTYPES[NUM_WINTYPES] = { "dnd", }; -struct timeval time_start = { 0, 0 }; - -win *list; -Display *dpy = NULL; -int scr; - -/// Root window. -Window root = None; -/// Damage of root window. -Damage root_damage = None; -/// X Composite overlay window. Used if --paint-on-overlay. -Window overlay = None; - -/// Picture of root window. Destination of painting in no-DBE painting -/// mode. -Picture root_picture = None; -/// A Picture acting as the painting target. -Picture tgt_picture = None; -/// Temporary buffer to paint to before sending to display. -Picture tgt_buffer = None; -/// DBE back buffer for root window. Used in DBE painting mode. -XdbeBackBuffer root_dbe = None; - -Picture black_picture; -Picture cshadow_picture; -/// Picture used for dimming inactive windows. -Picture dim_picture = 0; -Picture root_tile; -XserverRegion all_damage; -Bool has_name_pixmap; -int root_height, root_width; -/// A region of the size of the screen. -XserverRegion screen_reg = None; -/// Current active window. Used by EWMH _NET_ACTIVE_WINDOW focus -/// detection. -win *active_win = NULL; -/// Whether all windows are currently redirected. -Bool redirected = False; -/// Whether there's a highest fullscreen window, and all windows could -/// be unredirected. -Bool unredir_possible = False; - -/// Pregenerated alpha pictures. -Picture *alpha_picts = NULL; -/// Whether the program is idling. I.e. no fading, no potential window -/// changes. -Bool idling; -/// Whether all reg_ignore of windows should expire in this paint. -Bool reg_ignore_expire = False; -/// Window ID of the window we register as a symbol. -Window reg_win = 0; - -/// Currently used refresh rate. Used for sw_opti. -short refresh_rate = 0; -/// Interval between refresh in nanoseconds. Used for sw_opti. -unsigned long refresh_intv = 0; -/// Nanosecond-level offset of the first painting. Used for sw_opti. -long paint_tm_offset = 0; - -#ifdef CONFIG_VSYNC_DRM -/// File descriptor of DRI device file. Used for DRM VSync. -int drm_fd = 0; -#endif - -#ifdef CONFIG_VSYNC_OPENGL -/// GLX context. -GLXContext glx_context; - -/// Pointer to glXGetVideoSyncSGI function. Used by OpenGL VSync. -f_GetVideoSync glx_get_video_sync = NULL; - -/// Pointer to glXWaitVideoSyncSGI function. Used by OpenGL VSync. -f_WaitVideoSync glx_wait_video_sync = NULL; -#endif - -/* errors */ -ignore *ignore_head = NULL, **ignore_tail = &ignore_head; -int xfixes_event, xfixes_error; -int damage_event, damage_error; -int composite_event, composite_error; -int render_event, render_error; -int composite_opcode; - -/// Whether X Shape extension exists. -Bool shape_exists = False; -/// Event base number and error base number for X Shape extension. -int shape_event, shape_error; - -/// Whether X RandR extension exists. -Bool randr_exists = False; -/// Event base number and error base number for X RandR extension. -int randr_event, randr_error; - -#ifdef CONFIG_VSYNC_OPENGL -/// Whether X GLX extension exists. -Bool glx_exists = False; -/// Event base number and error base number for X GLX extension. -int glx_event, glx_error; -#endif - -Bool dbe_exists = False; - -/* shadows */ -conv *gaussian_map; - -/* for shadow precomputation */ -int cgsize = -1; -unsigned char *shadow_corner = NULL; -unsigned char *shadow_top = NULL; - -/* for root tile */ -static const char *background_props[] = { +/// Names of root window properties that could point to a pixmap of +/// background. +const char *background_props_str[] = { "_XROOTPMAP_ID", "_XSETROOT_ID", 0, }; -/* for expose events */ -XRectangle *expose_rects = 0; -int size_expose = 0; -int n_expose = 0; +// === Global variables === -// atoms -Atom opacity_atom = None; -Atom frame_extents_atom = None; -Atom client_atom = None; -Atom name_atom = None; -Atom name_ewmh_atom = None; -Atom class_atom = None; -Atom transient_atom = None; -Atom ewmh_active_win_atom = None;; -Atom compton_shadow_atom = None; +/// Pointer to current session, as a global variable. Only used by +/// error() and reset_enable(), which could not +/// have a pointer to current session passed in. +session_t *ps_g = NULL; -Atom win_type_atom; -Atom win_type[NUM_WINTYPES]; - -/** - * Macros - */ - -#define HAS_FRAME_OPACITY(w) \ - (frame_opacity && (w)->top_width) - -/** - * Options - */ - -static options_t opts = { - .display = NULL, - .mark_wmwin_focused = False, - .mark_ovredir_focused = False, - .fork_after_register = False, - .synchronize = False, - .detect_rounded_corners = False, - .paint_on_overlay = False, - .unredir_if_possible = False, - - .refresh_rate = 0, - .sw_opti = False, - .vsync = VSYNC_NONE, - .dbe = False, - .vsync_aggressive = False, - - .wintype_shadow = { False }, - .shadow_red = 0.0, - .shadow_green = 0.0, - .shadow_blue = 0.0, - .shadow_radius = 12, - .shadow_offset_x = -15, - .shadow_offset_y = -15, - .shadow_opacity = .75, - .clear_shadow = False, - .shadow_blacklist = NULL, - .shadow_ignore_shaped = False, - .respect_attr_shadow = False, - - .wintype_fade = { False }, - .fade_in_step = 0.028 * OPAQUE, - .fade_out_step = 0.03 * OPAQUE, - .fade_delta = 10, - .no_fading_openclose = False, - .fade_blacklist = NULL, - - .wintype_opacity = { 0.0 }, - .inactive_opacity = 0, - .inactive_opacity_override = False, - .frame_opacity = 0.0, - .detect_client_opacity = False, - .inactive_dim = 0.0, - .alpha_step = 0.03, - .use_ewmh_active_win = False, - - .track_focus = False, - .track_wdata = False, -}; - -/** - * Fades - */ - -unsigned long fade_time = 0; +// === Fading === /** * Get the time left before next fading point. @@ -246,8 +63,8 @@ unsigned long fade_time = 0; * In milliseconds. */ static int -fade_timeout(void) { - int diff = opts.fade_delta - get_time_ms() + fade_time; +fade_timeout(session_t *ps) { + int diff = ps->o.fade_delta - get_time_ms() + ps->fade_time; if (diff < 0) diff = 0; @@ -261,7 +78,7 @@ fade_timeout(void) { * @param steps steps of fading */ static void -run_fade(Display *dpy, win *w, unsigned steps) { +run_fade(session_t *ps, win *w, unsigned steps) { // If we have reached target opacity, return if (w->opacity == w->opacity_tgt) { return; @@ -274,16 +91,16 @@ run_fade(Display *dpy, win *w, unsigned steps) { // calculations if (w->opacity < w->opacity_tgt) w->opacity = normalize_d_range( - (double) w->opacity + (double) opts.fade_in_step * steps, + (double) w->opacity + (double) ps->o.fade_in_step * steps, 0.0, w->opacity_tgt); else w->opacity = normalize_d_range( - (double) w->opacity - (double) opts.fade_out_step * steps, + (double) w->opacity - (double) ps->o.fade_out_step * steps, w->opacity_tgt, OPAQUE); } if (w->opacity != w->opacity_tgt) { - idling = False; + ps->idling = false; } } @@ -294,32 +111,30 @@ run_fade(Display *dpy, win *w, unsigned steps) { * @param exec_callback whether the previous callback is to be executed */ static void -set_fade_callback(Display *dpy, win *w, - void (*callback) (Display *dpy, win *w), Bool exec_callback) { - void (*old_callback) (Display *dpy, win *w) = w->fade_callback; +set_fade_callback(session_t *ps, win *w, + void (*callback) (session_t *ps, win *w), bool exec_callback) { + void (*old_callback) (session_t *ps, win *w) = w->fade_callback; w->fade_callback = callback; // Must be the last line as the callback could destroy w! if (exec_callback && old_callback) { - old_callback(dpy, w); + old_callback(ps, w); // Although currently no callback function affects window state on // next paint, it could, in the future - idling = False; + ps->idling = false; } } -/** - * Shadows - */ +// === Shadows === -static double +static double __attribute__((const)) gaussian(double r, double x, double y) { return ((1 / (sqrt(2 * M_PI * r))) * exp((- (x * x + y * y)) / (2 * r * r))); } static conv * -make_gaussian_map(Display *dpy, double r) { +make_gaussian_map(double r) { conv *c; int size = ((int) ceil((r * 3)) + 1) & ~1; int center = size / 2; @@ -334,7 +149,7 @@ make_gaussian_map(Display *dpy, double r) { for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { - g = gaussian(r, (double) (x - center), (double) (y - center)); + g = gaussian(r, x - center, y - center); t += g; c->data[y * size + x] = g; } @@ -420,54 +235,56 @@ sum_gaussian(conv *map, double opacity, to save time for large windows */ static void -presum_gaussian(conv *map) { +presum_gaussian(session_t *ps, conv *map) { int center = map->size / 2; int opacity, x, y; - cgsize = map->size; + ps->cgsize = map->size; - if (shadow_corner) free((void *)shadow_corner); - if (shadow_top) free((void *)shadow_top); + if (ps->shadow_corner) + free(ps->shadow_corner); + if (ps->shadow_top) + free(ps->shadow_top); - shadow_corner = (unsigned char *)(malloc((cgsize + 1) * (cgsize + 1) * 26)); - shadow_top = (unsigned char *)(malloc((cgsize + 1) * 26)); + ps->shadow_corner = malloc((ps->cgsize + 1) * (ps->cgsize + 1) * 26); + ps->shadow_top = malloc((ps->cgsize + 1) * 26); - for (x = 0; x <= cgsize; x++) { - shadow_top[25 * (cgsize + 1) + x] = - sum_gaussian(map, 1, x - center, center, cgsize * 2, cgsize * 2); + for (x = 0; x <= ps->cgsize; x++) { + ps->shadow_top[25 * (ps->cgsize + 1) + x] = + sum_gaussian(map, 1, x - center, center, ps->cgsize * 2, ps->cgsize * 2); for (opacity = 0; opacity < 25; opacity++) { - shadow_top[opacity * (cgsize + 1) + x] = - shadow_top[25 * (cgsize + 1) + x] * opacity / 25; + ps->shadow_top[opacity * (ps->cgsize + 1) + x] = + ps->shadow_top[25 * (ps->cgsize + 1) + x] * opacity / 25; } for (y = 0; y <= x; y++) { - shadow_corner[25 * (cgsize + 1) * (cgsize + 1) + y * (cgsize + 1) + x] - = sum_gaussian(map, 1, x - center, y - center, cgsize * 2, cgsize * 2); - shadow_corner[25 * (cgsize + 1) * (cgsize + 1) + x * (cgsize + 1) + y] - = shadow_corner[25 * (cgsize + 1) * (cgsize + 1) + y * (cgsize + 1) + x]; + ps->shadow_corner[25 * (ps->cgsize + 1) * (ps->cgsize + 1) + y * (ps->cgsize + 1) + x] + = sum_gaussian(map, 1, x - center, y - center, ps->cgsize * 2, ps->cgsize * 2); + ps->shadow_corner[25 * (ps->cgsize + 1) * (ps->cgsize + 1) + x * (ps->cgsize + 1) + y] + = ps->shadow_corner[25 * (ps->cgsize + 1) * (ps->cgsize + 1) + y * (ps->cgsize + 1) + x]; for (opacity = 0; opacity < 25; opacity++) { - shadow_corner[opacity * (cgsize + 1) * (cgsize + 1) - + y * (cgsize + 1) + x] - = shadow_corner[opacity * (cgsize + 1) * (cgsize + 1) - + x * (cgsize + 1) + y] - = shadow_corner[25 * (cgsize + 1) * (cgsize + 1) - + y * (cgsize + 1) + x] * opacity / 25; + ps->shadow_corner[opacity * (ps->cgsize + 1) * (ps->cgsize + 1) + + y * (ps->cgsize + 1) + x] + = ps->shadow_corner[opacity * (ps->cgsize + 1) * (ps->cgsize + 1) + + x * (ps->cgsize + 1) + y] + = ps->shadow_corner[25 * (ps->cgsize + 1) * (ps->cgsize + 1) + + y * (ps->cgsize + 1) + x] * opacity / 25; } } } } static XImage * -make_shadow(Display *dpy, double opacity, - int width, int height, Bool clear_shadow) { +make_shadow(session_t *ps, double opacity, + int width, int height) { XImage *ximage; unsigned char *data; int ylimit, xlimit; - int swidth = width + cgsize; - int sheight = height + cgsize; - int center = cgsize / 2; + int swidth = width + ps->cgsize; + int sheight = height + ps->cgsize; + int center = ps->cgsize / 2; int x, y; unsigned char d; int x_diff; @@ -476,10 +293,8 @@ make_shadow(Display *dpy, double opacity, data = malloc(swidth * sheight * sizeof(unsigned char)); if (!data) return 0; - ximage = XCreateImage( - dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 8, - ZPixmap, 0, (char *) data, swidth, sheight, 8, - swidth * sizeof(unsigned char)); + ximage = XCreateImage(ps->dpy, ps->vis, 8, + ZPixmap, 0, (char *) data, swidth, sheight, 8, swidth * sizeof(char)); if (!ximage) { free(data); @@ -498,12 +313,12 @@ make_shadow(Display *dpy, double opacity, // later will be filled) could entirely cover the area of the shadow // that will be displayed, do not bother filling other pixels. If it // can't, we must fill the other pixels here. - /* if (!(clear_shadow && opts.shadow_offset_x <= 0 && opts.shadow_offset_x >= -cgsize - && opts.shadow_offset_y <= 0 && opts.shadow_offset_y >= -cgsize)) { */ - if (cgsize > 0) { - d = shadow_top[opacity_int * (cgsize + 1) + cgsize]; + /* if (!(clear_shadow && ps->o.shadow_offset_x <= 0 && ps->o.shadow_offset_x >= -ps->cgsize + && ps->o.shadow_offset_y <= 0 && ps->o.shadow_offset_y >= -ps->cgsize)) { */ + if (ps->cgsize > 0) { + d = ps->shadow_top[opacity_int * (ps->cgsize + 1) + ps->cgsize]; } else { - d = sum_gaussian(gaussian_map, + d = sum_gaussian(ps->gaussian_map, opacity, center, center, width, height); } memset(data, d, sheight * swidth); @@ -513,19 +328,19 @@ make_shadow(Display *dpy, double opacity, * corners */ - ylimit = cgsize; + ylimit = ps->cgsize; if (ylimit > sheight / 2) ylimit = (sheight + 1) / 2; - xlimit = cgsize; + xlimit = ps->cgsize; if (xlimit > swidth / 2) xlimit = (swidth + 1) / 2; for (y = 0; y < ylimit; y++) { for (x = 0; x < xlimit; x++) { - if (xlimit == cgsize && ylimit == cgsize) { - d = shadow_corner[opacity_int * (cgsize + 1) * (cgsize + 1) - + y * (cgsize + 1) + x]; + if (xlimit == ps->cgsize && ylimit == ps->cgsize) { + d = ps->shadow_corner[opacity_int * (ps->cgsize + 1) * (ps->cgsize + 1) + + y * (ps->cgsize + 1) + x]; } else { - d = sum_gaussian(gaussian_map, + d = sum_gaussian(ps->gaussian_map, opacity, x - center, y - center, width, height); } data[y * swidth + x] = d; @@ -539,17 +354,17 @@ make_shadow(Display *dpy, double opacity, * top/bottom */ - x_diff = swidth - (cgsize * 2); + x_diff = swidth - (ps->cgsize * 2); if (x_diff > 0 && ylimit > 0) { for (y = 0; y < ylimit; y++) { - if (ylimit == cgsize) { - d = shadow_top[opacity_int * (cgsize + 1) + y]; + if (ylimit == ps->cgsize) { + d = ps->shadow_top[opacity_int * (ps->cgsize + 1) + y]; } else { - d = sum_gaussian(gaussian_map, + d = sum_gaussian(ps->gaussian_map, opacity, center, y - center, width, height); } - memset(&data[y * swidth + cgsize], d, x_diff); - memset(&data[(sheight - y - 1) * swidth + cgsize], d, x_diff); + memset(&data[y * swidth + ps->cgsize], d, x_diff); + memset(&data[(sheight - y - 1) * swidth + ps->cgsize], d, x_diff); } } @@ -558,28 +373,27 @@ make_shadow(Display *dpy, double opacity, */ for (x = 0; x < xlimit; x++) { - if (xlimit == cgsize) { - d = shadow_top[opacity_int * (cgsize + 1) + x]; + if (xlimit == ps->cgsize) { + d = ps->shadow_top[opacity_int * (ps->cgsize + 1) + x]; } else { - d = sum_gaussian(gaussian_map, + d = sum_gaussian(ps->gaussian_map, opacity, x - center, center, width, height); } - for (y = cgsize; y < sheight - cgsize; y++) { + for (y = ps->cgsize; y < sheight - ps->cgsize; y++) { data[y * swidth + x] = d; data[y * swidth + (swidth - x - 1)] = d; } } - assert(!clear_shadow); /* if (clear_shadow) { // Clear the region in the shadow that the window would cover based // on shadow_offset_{x,y} user provides - int xstart = normalize_i_range(- (int) opts.shadow_offset_x, 0, swidth); - int xrange = normalize_i_range(width - (int) opts.shadow_offset_x, + int xstart = normalize_i_range(- (int) ps->o.shadow_offset_x, 0, swidth); + int xrange = normalize_i_range(width - (int) ps->o.shadow_offset_x, 0, swidth) - xstart; - int ystart = normalize_i_range(- (int) opts.shadow_offset_y, 0, sheight); - int yend = normalize_i_range(height - (int) opts.shadow_offset_y, + int ystart = normalize_i_range(- (int) ps->o.shadow_offset_y, 0, sheight); + int yend = normalize_i_range(height - (int) ps->o.shadow_offset_y, 0, sheight); int y; @@ -592,48 +406,50 @@ make_shadow(Display *dpy, double opacity, return ximage; } +/** + * Generate shadow Picture for a window. + */ static Picture -shadow_picture(Display *dpy, double opacity, int width, int height, - Bool clear_shadow) { +shadow_picture(session_t *ps, double opacity, int width, int height) { XImage *shadow_image = NULL; Pixmap shadow_pixmap = None, shadow_pixmap_argb = None; Picture shadow_picture = None, shadow_picture_argb = None; GC gc = None; - shadow_image = make_shadow(dpy, opacity, width, height, clear_shadow); + shadow_image = make_shadow(ps, opacity, width, height); if (!shadow_image) return None; - shadow_pixmap = XCreatePixmap(dpy, root, + shadow_pixmap = XCreatePixmap(ps->dpy, ps->root, shadow_image->width, shadow_image->height, 8); - shadow_pixmap_argb = XCreatePixmap(dpy, root, + shadow_pixmap_argb = XCreatePixmap(ps->dpy, ps->root, shadow_image->width, shadow_image->height, 32); if (!shadow_pixmap || !shadow_pixmap_argb) goto shadow_picture_err; - shadow_picture = XRenderCreatePicture(dpy, shadow_pixmap, - XRenderFindStandardFormat(dpy, PictStandardA8), 0, 0); - shadow_picture_argb = XRenderCreatePicture(dpy, shadow_pixmap_argb, - XRenderFindStandardFormat(dpy, PictStandardARGB32), 0, 0); + shadow_picture = XRenderCreatePicture(ps->dpy, shadow_pixmap, + XRenderFindStandardFormat(ps->dpy, PictStandardA8), 0, 0); + shadow_picture_argb = XRenderCreatePicture(ps->dpy, shadow_pixmap_argb, + XRenderFindStandardFormat(ps->dpy, PictStandardARGB32), 0, 0); if (!shadow_picture || !shadow_picture_argb) goto shadow_picture_err; - gc = XCreateGC(dpy, shadow_pixmap, 0, 0); + gc = XCreateGC(ps->dpy, shadow_pixmap, 0, 0); if (!gc) goto shadow_picture_err; - XPutImage(dpy, shadow_pixmap, gc, shadow_image, 0, 0, 0, 0, + XPutImage(ps->dpy, shadow_pixmap, gc, shadow_image, 0, 0, 0, 0, shadow_image->width, shadow_image->height); - XRenderComposite(dpy, PictOpSrc, cshadow_picture, shadow_picture, + XRenderComposite(ps->dpy, PictOpSrc, ps->cshadow_picture, shadow_picture, shadow_picture_argb, 0, 0, 0, 0, 0, 0, shadow_image->width, shadow_image->height); - XFreeGC(dpy, gc); + XFreeGC(ps->dpy, gc); XDestroyImage(shadow_image); - XFreePixmap(dpy, shadow_pixmap); - XFreePixmap(dpy, shadow_pixmap_argb); - XRenderFreePicture(dpy, shadow_picture); + XFreePixmap(ps->dpy, shadow_pixmap); + XFreePixmap(ps->dpy, shadow_pixmap_argb); + XRenderFreePicture(ps->dpy, shadow_picture); return shadow_picture_argb; @@ -641,39 +457,42 @@ shadow_picture_err: if (shadow_image) XDestroyImage(shadow_image); if (shadow_pixmap) - XFreePixmap(dpy, shadow_pixmap); + XFreePixmap(ps->dpy, shadow_pixmap); if (shadow_pixmap_argb) - XFreePixmap(dpy, shadow_pixmap_argb); + XFreePixmap(ps->dpy, shadow_pixmap_argb); if (shadow_picture) - XRenderFreePicture(dpy, shadow_picture); + XRenderFreePicture(ps->dpy, shadow_picture); if (shadow_picture_argb) - XRenderFreePicture(dpy, shadow_picture_argb); + XRenderFreePicture(ps->dpy, shadow_picture_argb); if (gc) - XFreeGC(dpy, gc); + XFreeGC(ps->dpy, gc); return None; } +/** + * Generate a 1x1 Picture of a particular color. + */ static Picture -solid_picture(Display *dpy, Bool argb, double a, +solid_picture(session_t *ps, bool argb, double a, double r, double g, double b) { Pixmap pixmap; Picture picture; XRenderPictureAttributes pa; XRenderColor c; - pixmap = XCreatePixmap(dpy, root, 1, 1, argb ? 32 : 8); + pixmap = XCreatePixmap(ps->dpy, ps->root, 1, 1, argb ? 32 : 8); if (!pixmap) return None; pa.repeat = True; - picture = XRenderCreatePicture(dpy, pixmap, - XRenderFindStandardFormat(dpy, argb + picture = XRenderCreatePicture(ps->dpy, pixmap, + XRenderFindStandardFormat(ps->dpy, argb ? PictStandardARGB32 : PictStandardA8), CPRepeat, &pa); if (!picture) { - XFreePixmap(dpy, pixmap); + XFreePixmap(ps->dpy, pixmap); return None; } @@ -682,25 +501,23 @@ solid_picture(Display *dpy, Bool argb, double a, c.green = g * 0xffff; c.blue = b * 0xffff; - XRenderFillRectangle(dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); - XFreePixmap(dpy, pixmap); + XRenderFillRectangle(ps->dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); + XFreePixmap(ps->dpy, pixmap); return picture; } -/** - * Errors - */ +// === Error handling === static void -discard_ignore(Display *dpy, unsigned long sequence) { - while (ignore_head) { - if ((long) (sequence - ignore_head->sequence) > 0) { - ignore *next = ignore_head->next; - free(ignore_head); - ignore_head = next; - if (!ignore_head) { - ignore_tail = &ignore_head; +discard_ignore(session_t *ps, unsigned long sequence) { + while (ps->ignore_head) { + if ((long) (sequence - ps->ignore_head->sequence) > 0) { + ignore_t *next = ps->ignore_head->next; + free(ps->ignore_head); + ps->ignore_head = next; + if (!ps->ignore_head) { + ps->ignore_tail = &ps->ignore_head; } } else { break; @@ -709,37 +526,35 @@ discard_ignore(Display *dpy, unsigned long sequence) { } static void -set_ignore(Display *dpy, unsigned long sequence) { - ignore *i = malloc(sizeof(ignore)); +set_ignore(session_t *ps, unsigned long sequence) { + ignore_t *i = malloc(sizeof(ignore_t)); if (!i) return; i->sequence = sequence; i->next = 0; - *ignore_tail = i; - ignore_tail = &i->next; + *ps->ignore_tail = i; + ps->ignore_tail = &i->next; } static int -should_ignore(Display *dpy, unsigned long sequence) { - discard_ignore(dpy, sequence); - return ignore_head && ignore_head->sequence == sequence; +should_ignore(session_t *ps, unsigned long sequence) { + discard_ignore(ps, sequence); + return ps->ignore_head && ps->ignore_head->sequence == sequence; } -/** - * Windows - */ +// === Windows === /** * Check if a window has rounded corners. */ static void -win_rounded_corners(Display *dpy, win *w) { +win_rounded_corners(session_t *ps, win *w) { if (!w->bounding_shaped) return; // Fetch its bounding region if (!w->border_size) - w->border_size = border_size(dpy, w); + w->border_size = border_size(ps, w); // Quit if border_size() returns None if (!w->border_size) @@ -754,7 +569,7 @@ win_rounded_corners(Display *dpy, win *w) { // Get the rectangles in the bounding region int nrects = 0, i; - XRectangle *rects = XFixesFetchRegion(dpy, w->border_size, &nrects); + XRectangle *rects = XFixesFetchRegion(ps->dpy, w->border_size, &nrects); if (!rects) return; @@ -762,12 +577,12 @@ win_rounded_corners(Display *dpy, win *w) { // having rounded corners for (i = 0; i < nrects; ++i) if (rects[i].width >= minwidth && rects[i].height >= minheight) { - w->rounded_corners = True; + w->rounded_corners = true; XFree(rects); return; } - w->rounded_corners = False; + w->rounded_corners = false; XFree(rects); } @@ -777,7 +592,7 @@ win_rounded_corners(Display *dpy, win *w) { * @return true if matched, false otherwise. */ static bool -win_match_once(win *w, const wincond *cond) { +win_match_once(win *w, const wincond_t *cond) { const char *target; bool matched = false; @@ -866,7 +681,7 @@ win_match_once(win *w, const wincond *cond) { * @return true if matched, false otherwise. */ static bool -win_match(win *w, wincond *condlst, wincond **cache) { +win_match(win *w, wincond_t *condlst, wincond_t **cache) { // Check if the cached entry matches firstly if (cache && *cache && win_match_once(w, *cache)) return true; @@ -886,22 +701,22 @@ win_match(win *w, wincond *condlst, wincond **cache) { /** * Add a pattern to a condition linked list. */ -static Bool -condlst_add(wincond **pcondlst, const char *pattern) { +static bool +condlst_add(wincond_t **pcondlst, const char *pattern) { if (!pattern) - return False; + return false; unsigned plen = strlen(pattern); - wincond *cond; + wincond_t *cond; const char *pos; if (plen < 4 || ':' != pattern[1] || !strchr(pattern + 2, ':')) { printf("Pattern \"%s\": Format invalid.\n", pattern); - return False; + return false; } // Allocate memory for the new condition - cond = malloc(sizeof(wincond)); + cond = malloc(sizeof(wincond_t)); // Determine the pattern target switch (pattern[0]) { @@ -918,7 +733,7 @@ condlst_add(wincond **pcondlst, const char *pattern) { printf("Pattern \"%s\": Target \"%c\" invalid.\n", pattern, pattern[0]); free(cond); - return False; + return false; } // Determine the pattern type @@ -944,7 +759,7 @@ condlst_add(wincond **pcondlst, const char *pattern) { printf("Pattern \"%s\": Type \"%c\" invalid.\n", pattern, pattern[2]); free(cond); - return False; + return false; } // Determine the pattern flags @@ -985,7 +800,7 @@ condlst_add(wincond **pcondlst, const char *pattern) { printf("Pattern \"%s\": PCRE regular expression parsing failed on " "offset %d: %s\n", pattern, erroffset, error); free(cond); - return False; + return false; } #ifdef CONFIG_REGEX_PCRE_JIT cond->regex_pcre_extra = pcre_study(cond->regex_pcre, PCRE_STUDY_JIT_COMPILE, &error); @@ -1004,33 +819,39 @@ condlst_add(wincond **pcondlst, const char *pattern) { cond->next = *pcondlst; *pcondlst = cond; - return True; + return true; } +/** + * Determine the event mask for a window. + */ static long -determine_evmask(Display *dpy, Window wid, win_evmode_t mode) { +determine_evmask(session_t *ps, Window wid, win_evmode_t mode) { long evmask = NoEventMask; - if (WIN_EVMODE_FRAME == mode || find_win(wid)) { + if (WIN_EVMODE_FRAME == mode || find_win(ps, wid)) { evmask |= PropertyChangeMask; - if (opts.track_focus && !opts.use_ewmh_active_win) + if (ps->o.track_focus && !ps->o.use_ewmh_active_win) evmask |= FocusChangeMask; } - if (WIN_EVMODE_CLIENT == mode || find_toplevel(wid)) { - if (opts.frame_opacity || opts.track_wdata - || opts.detect_client_opacity) + if (WIN_EVMODE_CLIENT == mode || find_toplevel(ps, wid)) { + if (ps->o.frame_opacity || ps->o.track_wdata + || ps->o.detect_client_opacity) evmask |= PropertyChangeMask; } return evmask; } +/** + * Find a window from window id in window linked list of the session. + */ static win * -find_win(Window id) { +find_win(session_t *ps, Window id) { win *w; - for (w = list; w; w = w->next) { + for (w = ps->list; w; w = w->next) { if (w->id == id && !w->destroyed) return w; } @@ -1045,10 +866,10 @@ find_win(Window id) { * @return struct _win object of the found window, NULL if not found */ static win * -find_toplevel(Window id) { +find_toplevel(session_t *ps, Window id) { win *w; - for (w = list; w; w = w->next) { + for (w = ps->list; w; w = w->next) { if (w->client_win == id && !w->destroyed) return w; } @@ -1059,16 +880,16 @@ find_toplevel(Window id) { /** * Find out the WM frame of a client window by querying X. * - * @param dpy display to use + * @param ps current session * @param w window ID * @return struct _win object of the found window, NULL if not found */ static win * -find_toplevel2(Display *dpy, Window wid) { +find_toplevel2(session_t *ps, Window wid) { win *w = NULL; // We traverse through its ancestors to find out the frame - while (wid && wid != root && !(w = find_win(wid))) { + while (wid && wid != ps->root && !(w = find_win(ps, wid))) { Window troot; Window parent; Window *tchildren; @@ -1077,7 +898,7 @@ find_toplevel2(Display *dpy, Window wid) { // XQueryTree probably fails if you run compton when X is somehow // initializing (like add it in .xinitrc). In this case // just leave it alone. - if (!XQueryTree(dpy, wid, &troot, &parent, &tchildren, + if (!XQueryTree(ps->dpy, wid, &troot, &parent, &tchildren, &tnchildren)) { parent = 0; break; @@ -1093,17 +914,17 @@ find_toplevel2(Display *dpy, Window wid) { /** * Recheck currently focused window and set its w->focused - * to True. + * to true. * - * @param dpy display to use + * @param ps current session * @return struct _win of currently focused window, NULL if not found */ static win * -recheck_focus(Display *dpy) { +recheck_focus(session_t *ps) { // Use EWMH _NET_ACTIVE_WINDOW if enabled - if (opts.use_ewmh_active_win) { - update_ewmh_active_win(dpy); - return active_win; + if (ps->o.use_ewmh_active_win) { + update_ewmh_active_win(ps); + return ps->active_win; } // Determine the currently focused window so we can apply appropriate @@ -1112,16 +933,16 @@ recheck_focus(Display *dpy) { int revert_to; win *w = NULL; - XGetInputFocus(dpy, &wid, &revert_to); + XGetInputFocus(ps->dpy, &wid, &revert_to); // Fallback to the old method if find_toplevel() fails - if (!(w = find_toplevel(wid))) { - w = find_toplevel2(dpy, wid); + if (!(w = find_toplevel(ps, wid))) { + w = find_toplevel2(ps, wid); } // And we set the focus state and opacity here if (w) { - set_focused(dpy, w, True); + set_focused(ps, w, true); return w; } @@ -1129,41 +950,42 @@ recheck_focus(Display *dpy) { } static Picture -root_tile_f(Display *dpy) { +root_tile_f(session_t *ps) { /* - if (opts.paint_on_overlay) { - return root_picture; + if (ps->o.paint_on_overlay) { + return ps->root_picture; } */ Picture picture; Pixmap pixmap; - Bool fill; + bool fill = false; XRenderPictureAttributes pa; int p; pixmap = None; // Get the values of background attributes - for (p = 0; background_props[p]; p++) { - winattr_t attr = wid_get_attr(dpy, root, - XInternAtom(dpy, background_props[p], False), 1L, XA_PIXMAP, 32); - if (attr.nitems) { - pixmap = *((long *) attr.data); - fill = False; - free_winattr(&attr); + for (p = 0; background_props_str[p]; p++) { + winprop_t prop = wid_get_prop(ps, ps->root, + XInternAtom(ps->dpy, background_props_str[p], false), + 1L, XA_PIXMAP, 32); + if (prop.nitems) { + pixmap = *((long *) prop.data); + fill = false; + free_winprop(&prop); break; } - free_winattr(&attr); + free_winprop(&prop); } if (!pixmap) { - pixmap = XCreatePixmap(dpy, root, 1, 1, DefaultDepth(dpy, scr)); - fill = True; + pixmap = XCreatePixmap(ps->dpy, ps->root, 1, 1, ps->depth); + fill = true; } - pa.repeat = True; + pa.repeat = true; picture = XRenderCreatePicture( - dpy, pixmap, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), + ps->dpy, pixmap, XRenderFindVisualFormat(ps->dpy, ps->vis), CPRepeat, &pa); if (fill) { @@ -1172,29 +994,32 @@ root_tile_f(Display *dpy) { c.red = c.green = c.blue = 0x8080; c.alpha = 0xffff; XRenderFillRectangle( - dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); + ps->dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); } return picture; } +/** + * Paint root window content. + */ static void -paint_root(Display *dpy) { - if (!root_tile) { - root_tile = root_tile_f(dpy); +paint_root(session_t *ps, Picture tgt_buffer) { + if (!ps->root_tile) { + ps->root_tile = root_tile_f(ps); } XRenderComposite( - dpy, PictOpSrc, root_tile, None, + ps->dpy, PictOpSrc, ps->root_tile, None, tgt_buffer, 0, 0, 0, 0, 0, 0, - root_width, root_height); + ps->root_width, ps->root_height); } /** * Get a rectangular region a window occupies, excluding shadow. */ static XserverRegion -win_get_region(Display *dpy, win *w) { +win_get_region(session_t *ps, win *w) { XRectangle r; r.x = w->a.x; @@ -1202,14 +1027,14 @@ win_get_region(Display *dpy, win *w) { r.width = w->widthb; r.height = w->heightb; - return XFixesCreateRegion(dpy, &r, 1); + return XFixesCreateRegion(ps->dpy, &r, 1); } /** * Get a rectangular region a window occupies, excluding frame and shadow. */ static XserverRegion -win_get_region_noframe(Display *dpy, win *w) { +win_get_region_noframe(session_t *ps, win *w) { XRectangle r; r.x = w->a.x + w->a.border_width + w->left_width; @@ -1218,9 +1043,9 @@ win_get_region_noframe(Display *dpy, win *w) { r.height = max_i(w->a.height - w->top_width - w->bottom_width, 0); if (r.width > 0 && r.height > 0) - return XFixesCreateRegion(dpy, &r, 1); + return XFixesCreateRegion(ps->dpy, &r, 1); else - return XFixesCreateRegion(dpy, NULL, 0); + return XFixesCreateRegion(ps->dpy, NULL, 0); } /** @@ -1230,7 +1055,7 @@ win_get_region_noframe(Display *dpy, win *w) { * function. */ static XserverRegion -win_extents(Display *dpy, win *w) { +win_extents(session_t *ps, win *w) { XRectangle r; r.x = w->a.x; @@ -1265,13 +1090,16 @@ win_extents(Display *dpy, win *w) { } } - return XFixesCreateRegion(dpy, &r, 1); + return XFixesCreateRegion(ps->dpy, &r, 1); } +/** + * Retrieve the bounding shape of a window. + */ static XserverRegion -border_size(Display *dpy, win *w) { +border_size(session_t *ps, win *w) { // Start with the window rectangular region - XserverRegion fin = win_get_region(dpy, w); + XserverRegion fin = win_get_region(ps, w); // Only request for a bounding region if the window is shaped if (w->bounding_shaped) { @@ -1284,29 +1112,32 @@ border_size(Display *dpy, win *w) { */ XserverRegion border = XFixesCreateRegionFromWindow( - dpy, w->id, WindowRegionBounding); + ps->dpy, w->id, WindowRegionBounding); if (!border) return fin; // Translate the region to the correct place - XFixesTranslateRegion(dpy, border, + XFixesTranslateRegion(ps->dpy, border, w->a.x + w->a.border_width, w->a.y + w->a.border_width); // Intersect the bounding region we got with the window rectangle, to // make sure the bounding region is not bigger than the window // rectangle - XFixesIntersectRegion(dpy, fin, fin, border); - XFixesDestroyRegion(dpy, border); + XFixesIntersectRegion(ps->dpy, fin, fin, border); + XFixesDestroyRegion(ps->dpy, border); } return fin; } +/** + * Look for the client window of a particular window. + */ static Window -find_client_win(Display *dpy, Window w) { - if (wid_has_attr(dpy, w, client_atom)) { +find_client_win(session_t *ps, Window w) { + if (wid_has_attr(ps, w, ps->atom_client)) { return w; } @@ -1315,12 +1146,12 @@ find_client_win(Display *dpy, Window w) { unsigned int i; Window ret = 0; - if (!wid_get_children(dpy, w, &children, &nchildren)) { + if (!wid_get_children(ps, w, &children, &nchildren)) { return 0; } for (i = 0; i < nchildren; ++i) { - if ((ret = find_client_win(dpy, children[i]))) + if ((ret = find_client_win(ps, children[i]))) break; } @@ -1329,60 +1160,70 @@ find_client_win(Display *dpy, Window w) { return ret; } +/** + * Retrieve frame extents from a window. + */ static void -get_frame_extents(Display *dpy, win *w, Window client) { +get_frame_extents(session_t *ps, win *w, Window client) { w->left_width = 0; w->right_width = 0; w->top_width = 0; w->bottom_width = 0; - winattr_t attr = wid_get_attr(dpy, client, frame_extents_atom, + winprop_t prop = wid_get_prop(ps, client, ps->atom_frame_extents, 4L, XA_CARDINAL, 32); - if (4 == attr.nitems) { - long *extents = (long *) attr.data; + if (4 == prop.nitems) { + long *extents = (long *) prop.data; w->left_width = extents[0]; w->right_width = extents[1]; w->top_width = extents[2]; w->bottom_width = extents[3]; - if (opts.frame_opacity) - update_reg_ignore_expire(w); + if (ps->o.frame_opacity) + update_reg_ignore_expire(ps, w); } - free_winattr(&attr); + free_winprop(&prop); } +/** + * Get alpha Picture for an opacity in double. + */ static inline Picture -get_alpha_pict_d(double o) { - assert((lround(normalize_d(o) / opts.alpha_step)) <= lround(1.0 / opts.alpha_step)); - return alpha_picts[lround(normalize_d(o) / opts.alpha_step)]; +get_alpha_pict_d(session_t *ps, double o) { + assert((lround(normalize_d(o) / ps->o.alpha_step)) <= lround(1.0 / ps->o.alpha_step)); + return ps->alpha_picts[lround(normalize_d(o) / ps->o.alpha_step)]; } +/** + * Get alpha Picture for an opacity in + * opacity_t. + */ static inline Picture -get_alpha_pict_o(opacity_t o) { - return get_alpha_pict_d((double) o / OPAQUE); +get_alpha_pict_o(session_t *ps, opacity_t o) { + return get_alpha_pict_d(ps, (double) o / OPAQUE); } static win * -paint_preprocess(Display *dpy, win *list) { +paint_preprocess(session_t *ps, win *list) { // Initialize unredir_possible - unredir_possible = False; + ps->unredir_possible = false; win *w; win *t = NULL, *next = NULL; // Trace whether it's the highest window to paint - Bool is_highest = True; + bool is_highest = true; // Fading step calculation - unsigned steps = (sub_unslong(get_time_ms(), fade_time) - + FADE_DELTA_TOLERANCE * opts.fade_delta) / opts.fade_delta; - fade_time += steps * opts.fade_delta; + unsigned steps = (sub_unslong(get_time_ms(), ps->fade_time) + + FADE_DELTA_TOLERANCE * ps->o.fade_delta) / ps->o.fade_delta; + ps->fade_time += steps * ps->o.fade_delta; XserverRegion last_reg_ignore = None; for (w = list; w; w = next) { - Bool to_paint = True; + bool to_paint = true; const winmode mode_old = w->mode; // In case calling the fade callback function destroys this window @@ -1390,123 +1231,123 @@ paint_preprocess(Display *dpy, win *list) { opacity_t opacity_old = w->opacity; // Destroy reg_ignore on all windows if they should expire - if (reg_ignore_expire) - free_region(dpy, &w->reg_ignore); + if (ps->reg_ignore_expire) + free_region(ps, &w->reg_ignore); // Run fading - run_fade(dpy, w, steps); + run_fade(ps, w, steps); // Give up if it's not damaged or invisible, or it's unmapped and its // picture is gone (for example due to a ConfigureNotify) if (!w->damaged || w->a.x + w->a.width < 1 || w->a.y + w->a.height < 1 - || w->a.x >= root_width || w->a.y >= root_height - || (IsUnmapped == w->a.map_state && !w->picture)) { - to_paint = False; + || w->a.x >= ps->root_width || w->a.y >= ps->root_height + || ((IsUnmapped == w->a.map_state || w->destroyed) + && !w->picture)) { + to_paint = false; } if (to_paint) { // If opacity changes if (w->opacity != opacity_old) { - determine_mode(dpy, w); - add_damage_win(dpy, w); + determine_mode(ps, w); + add_damage_win(ps, w); } - w->alpha_pict = get_alpha_pict_o(w->opacity); + w->alpha_pict = get_alpha_pict_o(ps, w->opacity); // End the game if we are using the 0 opacity alpha_pict - if (w->alpha_pict == alpha_picts[0]) { - to_paint = False; + if (w->alpha_pict == ps->alpha_picts[0]) { + to_paint = false; } } if (to_paint) { // Fetch bounding region if (!w->border_size) { - w->border_size = border_size(dpy, w); + w->border_size = border_size(ps, w); } // Fetch window extents if (!w->extents) { - w->extents = win_extents(dpy, w); + w->extents = win_extents(ps, w); // If w->extents does not exist, the previous add_damage_win() // call when opacity changes has no effect, so redo it here. if (w->opacity != opacity_old) - add_damage_win(dpy, w); + add_damage_win(ps, w); } // Calculate frame_opacity { double frame_opacity_old = w->frame_opacity; - if (opts.frame_opacity && 1.0 != opts.frame_opacity + if (ps->o.frame_opacity && 1.0 != ps->o.frame_opacity && win_has_frame(w)) - w->frame_opacity = get_opacity_percent(dpy, w) * - opts.frame_opacity; + w->frame_opacity = get_opacity_percent(w) * + ps->o.frame_opacity; else w->frame_opacity = 0.0; if (w->to_paint && WINDOW_SOLID == mode_old && (0.0 == frame_opacity_old) != (0.0 == w->frame_opacity)) - reg_ignore_expire = True; + ps->reg_ignore_expire = true; } - w->frame_alpha_pict = get_alpha_pict_d(w->frame_opacity); + w->frame_alpha_pict = get_alpha_pict_d(ps, w->frame_opacity); // Calculate shadow opacity if (w->frame_opacity) - w->shadow_opacity = opts.shadow_opacity * w->frame_opacity; + w->shadow_opacity = ps->o.shadow_opacity * w->frame_opacity; else - w->shadow_opacity = opts.shadow_opacity * get_opacity_percent(dpy, w); + w->shadow_opacity = ps->o.shadow_opacity * get_opacity_percent(w); // Rebuild shadow_pict if necessary if (w->flags & WFLAG_SIZE_CHANGE) - free_picture(dpy, &w->shadow_pict); + free_picture(ps, &w->shadow_pict); if (w->shadow && !w->shadow_pict) { - w->shadow_pict = shadow_picture(dpy, 1, - w->widthb, w->heightb, False); + w->shadow_pict = shadow_picture(ps, 1, w->widthb, w->heightb); } - w->shadow_alpha_pict = get_alpha_pict_d(w->shadow_opacity); + w->shadow_alpha_pict = get_alpha_pict_d(ps, w->shadow_opacity); } if ((to_paint && WINDOW_SOLID == w->mode) != (w->to_paint && WINDOW_SOLID == mode_old)) - reg_ignore_expire = True; + ps->reg_ignore_expire = true; // Add window to damaged area if its painting status changes if (to_paint != w->to_paint) - add_damage_win(dpy, w); + add_damage_win(ps, w); if (to_paint) { // Generate ignore region for painting to reduce GPU load - if (reg_ignore_expire || !w->to_paint) { - free_region(dpy, &w->reg_ignore); + if (ps->reg_ignore_expire || !w->to_paint) { + free_region(ps, &w->reg_ignore); // If the window is solid, we add the window region to the // ignored region if (WINDOW_SOLID == w->mode) { if (!w->frame_opacity) { if (w->border_size) - w->reg_ignore = copy_region(dpy, w->border_size); + w->reg_ignore = copy_region(ps, w->border_size); else - w->reg_ignore = win_get_region(dpy, w); + w->reg_ignore = win_get_region(ps, w); } else { - w->reg_ignore = win_get_region_noframe(dpy, w); + w->reg_ignore = win_get_region_noframe(ps, w); if (w->border_size) - XFixesIntersectRegion(dpy, w->reg_ignore, w->reg_ignore, + XFixesIntersectRegion(ps->dpy, w->reg_ignore, w->reg_ignore, w->border_size); } if (last_reg_ignore) - XFixesUnionRegion(dpy, w->reg_ignore, w->reg_ignore, + XFixesUnionRegion(ps->dpy, w->reg_ignore, w->reg_ignore, last_reg_ignore); } // Otherwise we copy the last region over else if (last_reg_ignore) - w->reg_ignore = copy_region(dpy, last_reg_ignore); + w->reg_ignore = copy_region(ps, last_reg_ignore); else w->reg_ignore = None; } @@ -1514,11 +1355,11 @@ paint_preprocess(Display *dpy, win *list) { last_reg_ignore = w->reg_ignore; if (is_highest && to_paint) { - is_highest = False; + is_highest = false; if (WINDOW_SOLID == w->mode && (!w->frame_opacity || !win_has_frame(w)) - && win_is_fullscreen(w)) - unredir_possible = True; + && win_is_fullscreen(ps, w)) + ps->unredir_possible = true; } // Reset flags @@ -1534,7 +1375,7 @@ paint_preprocess(Display *dpy, win *list) { t = w; } else { - check_fade_fin(dpy, w); + check_fade_fin(ps, w); } if (!destroyed) @@ -1542,15 +1383,15 @@ paint_preprocess(Display *dpy, win *list) { } // If possible, unredirect all windows and stop painting - if (opts.unredir_if_possible && unredir_possible) { - redir_stop(dpy); + if (ps->o.unredir_if_possible && ps->unredir_possible) { + redir_stop(ps); } else { - redir_start(dpy); + redir_start(ps); } // Fetch pictures only if windows are redirected - if (redirected) { + if (ps->redirected) { for (w = t; w; w = w->prev_trans) { // Fetch the picture and pixmap if needed if (!w->picture) { @@ -1558,16 +1399,16 @@ paint_preprocess(Display *dpy, win *list) { XRenderPictFormat *format; Drawable draw = w->id; - if (has_name_pixmap && !w->pixmap) { - set_ignore(dpy, NextRequest(dpy)); - w->pixmap = XCompositeNameWindowPixmap(dpy, w->id); + if (ps->has_name_pixmap && !w->pixmap) { + set_ignore_next(ps); + w->pixmap = XCompositeNameWindowPixmap(ps->dpy, w->id); } if (w->pixmap) draw = w->pixmap; - format = XRenderFindVisualFormat(dpy, w->a.visual); + format = XRenderFindVisualFormat(ps->dpy, w->a.visual); pa.subwindow_mode = IncludeInferiors; w->picture = XRenderCreatePicture( - dpy, draw, format, CPSubwindowMode, &pa); + ps->dpy, draw, format, CPSubwindowMode, &pa); } } } @@ -1579,9 +1420,9 @@ paint_preprocess(Display *dpy, win *list) { * Paint the shadow of a window. */ static inline void -win_paint_shadow(Display *dpy, win *w, Picture tgt_buffer) { +win_paint_shadow(session_t *ps, win *w, Picture tgt_buffer) { XRenderComposite( - dpy, PictOpOver, w->shadow_pict, w->shadow_alpha_pict, + ps->dpy, PictOpOver, w->shadow_pict, w->shadow_alpha_pict, tgt_buffer, 0, 0, 0, 0, w->a.x + w->shadow_dx, w->a.y + w->shadow_dy, w->shadow_width, w->shadow_height); @@ -1591,7 +1432,7 @@ win_paint_shadow(Display *dpy, win *w, Picture tgt_buffer) { * Paint a window itself and dim it if asked. */ static inline void -win_paint_win(Display *dpy, win *w, Picture tgt_buffer) { +win_paint_win(session_t *ps, win *w, Picture tgt_buffer) { int x = w->a.x; int y = w->a.y; int wid = w->widthb; @@ -1601,7 +1442,7 @@ win_paint_win(Display *dpy, win *w, Picture tgt_buffer) { int op = (w->mode == WINDOW_SOLID ? PictOpSrc: PictOpOver); if (!w->frame_opacity) { - XRenderComposite(dpy, op, w->picture, alpha_mask, + XRenderComposite(ps->dpy, op, w->picture, alpha_mask, tgt_buffer, 0, 0, 0, 0, x, y, wid, hei); } else { @@ -1611,7 +1452,7 @@ win_paint_win(Display *dpy, win *w, Picture tgt_buffer) { int r = w->right_width; #define COMP_BDR(cx, cy, cwid, chei) \ - XRenderComposite(dpy, PictOpOver, w->picture, w->frame_alpha_pict, \ + XRenderComposite(ps->dpy, PictOpOver, w->picture, w->frame_alpha_pict, \ tgt_buffer, (cx), (cy), 0, 0, x + (cx), y + (cy), (cwid), (chei)) // The following complicated logic is required because some broken @@ -1647,7 +1488,7 @@ win_paint_win(Display *dpy, win *w, Picture tgt_buffer) { pwid = wid - l - pwid; if (pwid > 0) { // body - XRenderComposite(dpy, op, w->picture, alpha_mask, + XRenderComposite(ps->dpy, op, w->picture, alpha_mask, tgt_buffer, l, t, 0, 0, x + l, y + t, pwid, phei); } } @@ -1659,7 +1500,7 @@ win_paint_win(Display *dpy, win *w, Picture tgt_buffer) { // Dimming the window if needed if (w->dim) { - XRenderComposite(dpy, PictOpOver, dim_picture, None, + XRenderComposite(ps->dpy, PictOpOver, ps->dim_picture, None, tgt_buffer, 0, 0, 0, 0, x, y, wid, hei); } } @@ -1668,14 +1509,14 @@ win_paint_win(Display *dpy, win *w, Picture tgt_buffer) { * Rebuild cached screen_reg. */ static void -rebuild_screen_reg(Display *dpy) { - if (screen_reg) - XFixesDestroyRegion(dpy, screen_reg); - screen_reg = get_screen_region(dpy); +rebuild_screen_reg(session_t *ps) { + if (ps->screen_reg) + XFixesDestroyRegion(ps->dpy, ps->screen_reg); + ps->screen_reg = get_screen_region(ps); } static void -paint_all(Display *dpy, XserverRegion region, win *t) { +paint_all(session_t *ps, XserverRegion region, win *t) { #ifdef DEBUG_REPAINT static struct timespec last_paint = { 0 }; #endif @@ -1684,67 +1525,67 @@ paint_all(Display *dpy, XserverRegion region, win *t) { XserverRegion reg_paint = None, reg_tmp = None, reg_tmp2 = None; if (!region) { - region = get_screen_region(dpy); + region = get_screen_region(ps); } else { // Remove the damaged area out of screen - XFixesIntersectRegion(dpy, region, region, screen_reg); + XFixesIntersectRegion(ps->dpy, region, region, ps->screen_reg); } #ifdef MONITOR_REPAINT // Note: MONITOR_REPAINT cannot work with DBE right now. - tgt_buffer = tgt_picture; + ps->tgt_buffer = ps->tgt_picture; #else - if (!tgt_buffer) { + if (!ps->tgt_buffer) { // DBE painting mode: Directly paint to a Picture of the back buffer - if (opts.dbe) { - tgt_buffer = XRenderCreatePicture(dpy, root_dbe, - XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), + if (ps->o.dbe) { + ps->tgt_buffer = XRenderCreatePicture(ps->dpy, ps->root_dbe, + XRenderFindVisualFormat(ps->dpy, ps->vis), 0, 0); } // No-DBE painting mode: Paint to an intermediate Picture then paint // the Picture to root window else { Pixmap root_pixmap = XCreatePixmap( - dpy, root, root_width, root_height, - DefaultDepth(dpy, scr)); + ps->dpy, ps->root, ps->root_width, ps->root_height, + ps->depth); - tgt_buffer = XRenderCreatePicture(dpy, root_pixmap, - XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), + ps->tgt_buffer = XRenderCreatePicture(ps->dpy, root_pixmap, + XRenderFindVisualFormat(ps->dpy, ps->vis), 0, 0); - XFreePixmap(dpy, root_pixmap); + XFreePixmap(ps->dpy, root_pixmap); } } #endif - XFixesSetPictureClipRegion(dpy, tgt_picture, 0, 0, region); + XFixesSetPictureClipRegion(ps->dpy, ps->tgt_picture, 0, 0, region); #ifdef MONITOR_REPAINT XRenderComposite( - dpy, PictOpSrc, black_picture, None, - tgt_picture, 0, 0, 0, 0, 0, 0, - root_width, root_height); + ps->dpy, PictOpSrc, ps->black_picture, None, + ps->tgt_picture, 0, 0, 0, 0, 0, 0, + ps->root_width, ps->root_height); #endif if (t && t->reg_ignore) { // Calculate the region upon which the root window is to be painted // based on the ignore region of the lowest window, if available - reg_paint = reg_tmp = XFixesCreateRegion(dpy, NULL, 0); - XFixesSubtractRegion(dpy, reg_paint, region, t->reg_ignore); + reg_paint = reg_tmp = XFixesCreateRegion(ps->dpy, NULL, 0); + XFixesSubtractRegion(ps->dpy, reg_paint, region, t->reg_ignore); } else { reg_paint = region; } - XFixesSetPictureClipRegion(dpy, tgt_buffer, 0, 0, reg_paint); + XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, reg_paint); - paint_root(dpy); + paint_root(ps, ps->tgt_buffer); // Create temporary regions for use during painting if (!reg_tmp) - reg_tmp = XFixesCreateRegion(dpy, NULL, 0); - reg_tmp2 = XFixesCreateRegion(dpy, NULL, 0); + reg_tmp = XFixesCreateRegion(ps->dpy, NULL, 0); + reg_tmp2 = XFixesCreateRegion(ps->dpy, NULL, 0); for (w = t; w; w = w->prev_trans) { // Painting shadow @@ -1756,28 +1597,28 @@ paint_all(Display *dpy, XserverRegion region, win *t) { // If it's the first cycle and reg_tmp2 is not ready, calculate // the paint region here reg_paint = reg_tmp; - XFixesSubtractRegion(dpy, reg_paint, region, w->reg_ignore); + XFixesSubtractRegion(ps->dpy, reg_paint, region, w->reg_ignore); } else { // Otherwise, used the cached region during last cycle reg_paint = reg_tmp2; } - XFixesIntersectRegion(dpy, reg_paint, reg_paint, w->extents); + XFixesIntersectRegion(ps->dpy, reg_paint, reg_paint, w->extents); } else { reg_paint = reg_tmp; - XFixesIntersectRegion(dpy, reg_paint, region, w->extents); + XFixesIntersectRegion(ps->dpy, reg_paint, region, w->extents); } // Clear the shadow here instead of in make_shadow() for saving GPU // power and handling shaped windows - if (opts.clear_shadow && w->border_size) - XFixesSubtractRegion(dpy, reg_paint, reg_paint, w->border_size); + if (ps->o.clear_shadow && w->border_size) + XFixesSubtractRegion(ps->dpy, reg_paint, reg_paint, w->border_size); // Detect if the region is empty before painting - if (region == reg_paint || !is_region_empty(dpy, reg_paint)) { - XFixesSetPictureClipRegion(dpy, tgt_buffer, 0, 0, reg_paint); + if (region == reg_paint || !is_region_empty(ps, reg_paint)) { + XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, reg_paint); - win_paint_shadow(dpy, w, tgt_buffer); + win_paint_shadow(ps, w, ps->tgt_buffer); } } @@ -1785,77 +1626,77 @@ paint_all(Display *dpy, XserverRegion region, win *t) { // window and the bounding region reg_paint = reg_tmp; if (w->prev_trans && w->prev_trans->reg_ignore) { - XFixesSubtractRegion(dpy, reg_paint, region, + XFixesSubtractRegion(ps->dpy, reg_paint, region, w->prev_trans->reg_ignore); // Copy the subtracted region to be used for shadow painting in next // cycle - XFixesCopyRegion(dpy, reg_tmp2, reg_paint); + XFixesCopyRegion(ps->dpy, reg_tmp2, reg_paint); if (w->border_size) - XFixesIntersectRegion(dpy, reg_paint, reg_paint, w->border_size); + XFixesIntersectRegion(ps->dpy, reg_paint, reg_paint, w->border_size); } else { if (w->border_size) - XFixesIntersectRegion(dpy, reg_paint, region, w->border_size); + XFixesIntersectRegion(ps->dpy, reg_paint, region, w->border_size); else reg_paint = region; } - if (!is_region_empty(dpy, reg_paint)) { - XFixesSetPictureClipRegion(dpy, tgt_buffer, 0, 0, reg_paint); + if (!is_region_empty(ps, reg_paint)) { + XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, reg_paint); // Painting the window - win_paint_win(dpy, w, tgt_buffer); + win_paint_win(ps, w, ps->tgt_buffer); } - check_fade_fin(dpy, w); + check_fade_fin(ps, w); } // Free up all temporary regions - XFixesDestroyRegion(dpy, region); - XFixesDestroyRegion(dpy, reg_tmp); - XFixesDestroyRegion(dpy, reg_tmp2); + XFixesDestroyRegion(ps->dpy, region); + XFixesDestroyRegion(ps->dpy, reg_tmp); + XFixesDestroyRegion(ps->dpy, reg_tmp2); // Do this as early as possible - if (!opts.dbe) - XFixesSetPictureClipRegion(dpy, tgt_buffer, 0, 0, None); + if (!ps->o.dbe) + XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, None); - if (VSYNC_NONE != opts.vsync) { + if (VSYNC_NONE != ps->o.vsync) { // Make sure all previous requests are processed to achieve best // effect - XSync(dpy, False); + XSync(ps->dpy, False); } // Wait for VBlank. We could do it aggressively (send the painting // request and XFlush() on VBlank) or conservatively (send the request // only on VBlank). - if (!opts.vsync_aggressive) - vsync_wait(); + if (!ps->o.vsync_aggressive) + vsync_wait(ps); // DBE painting mode, only need to swap the buffer - if (opts.dbe) { + if (ps->o.dbe) { XdbeSwapInfo swap_info = { - .swap_window = (opts.paint_on_overlay ? overlay: root), + .swap_window = (ps->o.paint_on_overlay ? ps->overlay: ps->root), // Is it safe to use XdbeUndefined? .swap_action = XdbeCopied }; - XdbeSwapBuffers(dpy, &swap_info, 1); + XdbeSwapBuffers(ps->dpy, &swap_info, 1); } // No-DBE painting mode - else if (tgt_buffer != tgt_picture) { + else if (ps->tgt_buffer != ps->tgt_picture) { XRenderComposite( - dpy, PictOpSrc, tgt_buffer, None, - tgt_picture, 0, 0, 0, 0, - 0, 0, root_width, root_height); + ps->dpy, PictOpSrc, ps->tgt_buffer, None, + ps->tgt_picture, 0, 0, 0, 0, + 0, 0, ps->root_width, ps->root_height); } - if (opts.vsync_aggressive) - vsync_wait(); + if (ps->o.vsync_aggressive) + vsync_wait(ps); - XFlush(dpy); + XFlush(ps->dpy); #ifdef DEBUG_REPAINT - print_timestamp(); + print_timestamp(ps); struct timespec now = get_time_timespec(); struct timespec diff = { 0 }; timespec_subtract(&diff, &now, &last_paint); @@ -1870,91 +1711,78 @@ paint_all(Display *dpy, XserverRegion region, win *t) { } static void -add_damage(Display *dpy, XserverRegion damage) { - if (all_damage) { - XFixesUnionRegion(dpy, all_damage, all_damage, damage); - XFixesDestroyRegion(dpy, damage); +add_damage(session_t *ps, XserverRegion damage) { + if (ps->all_damage) { + XFixesUnionRegion(ps->dpy, ps->all_damage, ps->all_damage, damage); + XFixesDestroyRegion(ps->dpy, damage); } else { - all_damage = damage; + ps->all_damage = damage; } } static void -repair_win(Display *dpy, win *w) { +repair_win(session_t *ps, win *w) { XserverRegion parts; if (!w->damaged) { - parts = win_extents(dpy, w); - set_ignore(dpy, NextRequest(dpy)); - XDamageSubtract(dpy, w->damage, None, None); + parts = win_extents(ps, w); + set_ignore_next(ps); + XDamageSubtract(ps->dpy, w->damage, None, None); } else { - parts = XFixesCreateRegion(dpy, 0, 0); - set_ignore(dpy, NextRequest(dpy)); - XDamageSubtract(dpy, w->damage, None, parts); - XFixesTranslateRegion(dpy, parts, + parts = XFixesCreateRegion(ps->dpy, 0, 0); + set_ignore_next(ps); + XDamageSubtract(ps->dpy, w->damage, None, parts); + XFixesTranslateRegion(ps->dpy, parts, w->a.x + w->a.border_width, w->a.y + w->a.border_width); } // Remove the part in the damage area that could be ignored - if (!reg_ignore_expire && w->prev_trans && w->prev_trans->reg_ignore) - XFixesSubtractRegion(dpy, parts, parts, w->prev_trans->reg_ignore); + if (!ps->reg_ignore_expire && w->prev_trans && w->prev_trans->reg_ignore) + XFixesSubtractRegion(ps->dpy, parts, parts, w->prev_trans->reg_ignore); - add_damage(dpy, parts); + add_damage(ps, parts); w->damaged = 1; } -static wintype -get_wintype_prop(Display *dpy, Window wid) { - Atom actual; - int format; - unsigned long n = 0, left, i; - long *data = NULL; - int j; +static wintype_t +wid_get_prop_wintype(session_t *ps, Window wid) { + int i, j; - set_ignore(dpy, NextRequest(dpy)); - if (Success != XGetWindowProperty( - dpy, wid, win_type_atom, 0L, 32L, False, XA_ATOM, - &actual, &format, &n, &left, (unsigned char **) &data) - || !data || !n) { - if (data) - XFree(data); - return WINTYPE_UNKNOWN; - } + set_ignore_next(ps); + winprop_t prop = wid_get_prop(ps, wid, ps->atom_win_type, 32L, XA_ATOM, 32); - for (i = 0; i < n; ++i) { + for (i = 0; i < prop.nitems; ++i) { for (j = 1; j < NUM_WINTYPES; ++j) { - if (win_type[j] == (Atom) data[i]) { - XFree(data); + if (ps->atoms_wintypes[j] == (Atom) ((long *) prop.data)[i]) { + free_winprop(&prop); return j; } } } - XFree(data); + free_winprop(&prop); return WINTYPE_UNKNOWN; } static void -map_win(Display *dpy, Window id, - unsigned long sequence, Bool fade, - Bool override_redirect) { - win *w = find_win(id); +map_win(session_t *ps, Window id, bool override_redirect) { + win *w = find_win(ps, id); // Don't care about window mapping if it's an InputOnly window if (!w || InputOnly == w->a.class) return; - w->focused = False; + w->focused = false; w->a.map_state = IsViewable; // Call XSelectInput() before reading properties so that no property // changes are lost - XSelectInput(dpy, id, determine_evmask(dpy, id, WIN_EVMODE_FRAME)); + XSelectInput(ps->dpy, id, determine_evmask(ps, id, WIN_EVMODE_FRAME)); // Notify compton when the shape of a window changes - if (shape_exists) { - XShapeSelectInput(dpy, id, ShapeNotifyMask); + if (ps->shape_exists) { + XShapeSelectInput(ps->dpy, id, ShapeNotifyMask); } // Detect client window here instead of in add_win() as the client @@ -1963,7 +1791,7 @@ map_win(Display *dpy, Window id, Window cw = 0; // Always recursively look for a window with WM_STATE, as Fluxbox // sets override-redirect flags on all frame windows. - cw = find_client_win(dpy, w->id); + cw = find_client_win(ps, w->id); #ifdef DEBUG_CLIENTWIN printf("find_client_win(%#010lx): client %#010lx\n", w->id, cw); #endif @@ -1976,18 +1804,18 @@ map_win(Display *dpy, Window id, #endif } if (cw) { - mark_client_win(dpy, w, cw); + mark_client_win(ps, w, cw); } } else { // Re-mark client window here - mark_client_win(dpy, w, w->client_win); + mark_client_win(ps, w, w->client_win); } // Workaround for _NET_WM_WINDOW_TYPE for Openbox menus, which is // set on a non-override-redirect window with no WM_STATE either if (!w->client_win && WINTYPE_UNKNOWN == w->window_type) - w->window_type = get_wintype_prop(dpy, w->id); + w->window_type = wid_get_prop_wintype(ps, w->id); #ifdef DEBUG_WINTYPE printf("map_win(%#010lx): type %s\n", @@ -1995,54 +1823,54 @@ map_win(Display *dpy, Window id, #endif // Detect if the window is shaped or has rounded corners - win_update_shape_raw(dpy, w); + win_update_shape_raw(ps, w); // Get window name and class if we are tracking them - if (opts.track_wdata) { - win_get_name(dpy, w); - win_get_class(dpy, w); + if (ps->o.track_wdata) { + win_get_name(ps, w); + win_get_class(ps, w); } - if (opts.track_focus) { + if (ps->o.track_focus) { // Occasionally compton does not seem able to get a FocusIn event from // a window just mapped. I suspect it's a timing issue again when the // XSelectInput() is called too late. We have to recheck the focused // window here. It makes no sense if we are using EWMH // _NET_ACTIVE_WINDOW. - if (!opts.use_ewmh_active_win) - recheck_focus(dpy); + if (!ps->o.use_ewmh_active_win) + recheck_focus(ps); // Consider a window without client window a WM window and mark it // focused if mark_wmwin_focused is on, or it's over-redirected and // mark_ovredir_focused is on - if ((opts.mark_wmwin_focused && !w->client_win) - || (opts.mark_ovredir_focused && w->id == w->client_win)) - w->focused = True; + if ((ps->o.mark_wmwin_focused && !w->client_win) + || (ps->o.mark_ovredir_focused && w->id == w->client_win)) + w->focused = true; } // Check for _COMPTON_SHADOW - if (opts.respect_attr_shadow) - win_update_attr_shadow_raw(dpy, w); + if (ps->o.respect_prop_shadow) + win_update_attr_shadow_raw(ps, w); // Many things above could affect shadow - determine_shadow(dpy, w); + determine_shadow(ps, w); // Fading in - calc_opacity(dpy, w, True); + calc_opacity(ps, w, true); // Set fading state - if (opts.no_fading_openclose) { - set_fade_callback(dpy, w, finish_map_win, True); + if (ps->o.no_fading_openclose) { + set_fade_callback(ps, w, finish_map_win, true); // Must be set after we execute the old fade callback, in case we // receive two continuous MapNotify for the same window - w->fade = False; + w->fade = false; } else { - set_fade_callback(dpy, w, NULL, True); - determine_fade(dpy, w); + set_fade_callback(ps, w, NULL, true); + determine_fade(ps, w); } - calc_dim(dpy, w); + calc_dim(ps, w); w->damaged = 1; @@ -2051,42 +1879,42 @@ map_win(Display *dpy, Window id, the window was unmapped, then configure the window to its correct place */ if (w->need_configure) { - configure_win(dpy, &w->queue_configure); + configure_win(ps, &w->queue_configure); } } static void -finish_map_win(Display *dpy, win *w) { - if (opts.no_fading_openclose) - determine_fade(dpy, w); +finish_map_win(session_t *ps, win *w) { + if (ps->o.no_fading_openclose) + determine_fade(ps, w); } static void -finish_unmap_win(Display *dpy, win *w) { +finish_unmap_win(session_t *ps, win *w) { w->damaged = 0; - update_reg_ignore_expire(w); + update_reg_ignore_expire(ps, w); if (w->extents != None) { /* destroys region */ - add_damage(dpy, w->extents); + add_damage(ps, w->extents); w->extents = None; } - free_pixmap(dpy, &w->pixmap); - free_picture(dpy, &w->picture); - free_region(dpy, &w->border_size); - free_picture(dpy, &w->shadow_pict); + free_pixmap(ps, &w->pixmap); + free_picture(ps, &w->picture); + free_region(ps, &w->border_size); + free_picture(ps, &w->shadow_pict); } static void -unmap_callback(Display *dpy, win *w) { - finish_unmap_win(dpy, w); +unmap_callback(session_t *ps, win *w) { + finish_unmap_win(ps, w); } static void -unmap_win(Display *dpy, Window id, Bool fade) { - win *w = find_win(id); +unmap_win(session_t *ps, Window id) { + win *w = find_win(ps, id); if (!w || IsUnmapped == w->a.map_state) return; @@ -2094,48 +1922,36 @@ unmap_win(Display *dpy, Window id, Bool fade) { // Fading out w->opacity_tgt = 0; - set_fade_callback(dpy, w, unmap_callback, False); - if (opts.no_fading_openclose) - w->fade = False; + set_fade_callback(ps, w, unmap_callback, false); + if (ps->o.no_fading_openclose) + w->fade = false; // don't care about properties anymore - // Will get BadWindow if the window is destroyed - set_ignore(dpy, NextRequest(dpy)); - XSelectInput(dpy, w->id, 0); - - if (w->client_win) { - set_ignore(dpy, NextRequest(dpy)); - XSelectInput(dpy, w->client_win, 0); - } + win_ev_stop(ps, w); } static opacity_t -wid_get_opacity_prop(Display *dpy, Window wid, opacity_t def) { - Atom actual; - int format; - unsigned long n, left; +wid_get_opacity_prop(session_t *ps, Window wid, opacity_t def) { + opacity_t val = def; - unsigned char *data; - int result = XGetWindowProperty( - dpy, wid, opacity_atom, 0L, 1L, False, - XA_CARDINAL, &actual, &format, &n, &left, &data); + winprop_t prop = wid_get_prop(ps, wid, ps->atom_opacity, 1L, + XA_CARDINAL, 32); - if (result == Success && data != NULL) { - opacity_t i = *((opacity_t *) data); - XFree(data); - return i; - } + if (prop.nitems) + val = *((long *) prop.data); - return def; + free_winprop(&prop); + + return val; } static double -get_opacity_percent(Display *dpy, win *w) { +get_opacity_percent(win *w) { return ((double) w->opacity) / OPAQUE; } static void -determine_mode(Display *dpy, win *w) { +determine_mode(session_t *ps, win *w) { winmode mode; XRenderPictFormat *format; @@ -2144,7 +1960,7 @@ determine_mode(Display *dpy, win *w) { if (w->a.class == InputOnly) { format = 0; } else { - format = XRenderFindVisualFormat(dpy, w->a.visual); + format = XRenderFindVisualFormat(ps->dpy, w->a.visual); } if (format && format->type == PictTypeDirect @@ -2180,7 +1996,7 @@ determine_mode(Display *dpy, win *w) { * refetched */ static void -calc_opacity(Display *dpy, win *w, Bool refetch_prop) { +calc_opacity(session_t *ps, win *w, bool refetch_prop) { opacity_t opacity; // Do nothing for unmapped window, calc_opacity() will be called @@ -2191,42 +2007,45 @@ calc_opacity(Display *dpy, win *w, Bool refetch_prop) { // Do not refetch the opacity window attribute unless necessary, this // is probably an expensive operation in some cases if (refetch_prop) { - w->opacity_prop = wid_get_opacity_prop(dpy, w->id, OPAQUE); - if (!opts.detect_client_opacity || !w->client_win + w->opacity_prop = wid_get_opacity_prop(ps, w->id, OPAQUE); + if (!ps->o.detect_client_opacity || !w->client_win || w->id == w->client_win) w->opacity_prop_client = OPAQUE; else - w->opacity_prop_client = wid_get_opacity_prop(dpy, w->client_win, + w->opacity_prop_client = wid_get_opacity_prop(ps, w->client_win, OPAQUE); } if (OPAQUE == (opacity = w->opacity_prop) && OPAQUE == (opacity = w->opacity_prop_client)) { - opacity = opts.wintype_opacity[w->window_type] * OPAQUE; + opacity = ps->o.wintype_opacity[w->window_type] * OPAQUE; } // Respect inactive_opacity in some cases - if (opts.inactive_opacity && is_normal_win(w) && False == w->focused - && (OPAQUE == opacity || opts.inactive_opacity_override)) { - opacity = opts.inactive_opacity; + if (ps->o.inactive_opacity && is_normal_win(w) && false == w->focused + && (OPAQUE == opacity || ps->o.inactive_opacity_override)) { + opacity = ps->o.inactive_opacity; } w->opacity_tgt = opacity; } +/** + * Determine whether a window is to be dimmed. + */ static void -calc_dim(Display *dpy, win *w) { - Bool dim; +calc_dim(session_t *ps, win *w) { + bool dim; - if (opts.inactive_dim && is_normal_win(w) && !(w->focused)) { - dim = True; + if (ps->o.inactive_dim && is_normal_win(w) && !(w->focused)) { + dim = true; } else { - dim = False; + dim = false; } if (dim != w->dim) { w->dim = dim; - add_damage_win(dpy, w); + add_damage_win(ps, w); } } @@ -2234,19 +2053,19 @@ calc_dim(Display *dpy, win *w) { * Determine if a window should fade on opacity change. */ static void -determine_fade(Display *dpy, win *w) { - w->fade = opts.wintype_fade[w->window_type]; +determine_fade(session_t *ps, win *w) { + w->fade = ps->o.wintype_fade[w->window_type]; } /** * Update window-shape. */ static void -win_update_shape_raw(Display *dpy, win *w) { - if (shape_exists) { - w->bounding_shaped = wid_bounding_shaped(dpy, w->id); - if (w->bounding_shaped && opts.detect_rounded_corners) - win_rounded_corners(dpy, w); +win_update_shape_raw(session_t *ps, win *w) { + if (ps->shape_exists) { + w->bounding_shaped = wid_bounding_shaped(ps, w->id); + if (w->bounding_shaped && ps->o.detect_rounded_corners) + win_rounded_corners(ps, w); } } @@ -2254,20 +2073,20 @@ win_update_shape_raw(Display *dpy, win *w) { * Update window-shape related information. */ static void -win_update_shape(Display *dpy, win *w) { - if (shape_exists) { - // Bool bounding_shaped_old = w->bounding_shaped; +win_update_shape(session_t *ps, win *w) { + if (ps->shape_exists) { + // bool bounding_shaped_old = w->bounding_shaped; - win_update_shape_raw(dpy, w); + win_update_shape_raw(ps, w); // Shadow state could be changed - determine_shadow(dpy, w); + determine_shadow(ps, w); /* // If clear_shadow state on the window possibly changed, destroy the old // shadow_pict - if (opts.clear_shadow && w->bounding_shaped != bounding_shaped_old) - free_picture(dpy, &w->shadow_pict); + if (ps->o.clear_shadow && w->bounding_shaped != bounding_shaped_old) + free_picture(ps, &w->shadow_pict); */ } } @@ -2278,18 +2097,18 @@ win_update_shape(Display *dpy, win *w) { * The property must be set on the outermost window, usually the WM frame. */ static void -win_update_attr_shadow_raw(Display *dpy, win *w) { - winattr_t attr = wid_get_attr(dpy, w->id, compton_shadow_atom, 1, +win_update_attr_shadow_raw(session_t *ps, win *w) { + winprop_t prop = wid_get_prop(ps, w->id, ps->atom_compton_shadow, 1, XA_CARDINAL, 32); - - if (!attr.nitems) { - free_winattr(&attr); - w->attr_shadow = -1; - return; + if (!prop.nitems) { + w->attr_shadow = -1; + } + else { + w->attr_shadow = *((long *) prop.data); } - w->attr_shadow = *((long *) attr.data); + free_winprop(&prop); } /** @@ -2297,13 +2116,13 @@ win_update_attr_shadow_raw(Display *dpy, win *w) { * things. */ static void -win_update_attr_shadow(Display *dpy, win *w) { +win_update_attr_shadow(session_t *ps, win *w) { long attr_shadow_old = w->attr_shadow; - win_update_attr_shadow_raw(dpy, w); + win_update_attr_shadow_raw(ps, w); if (w->attr_shadow != attr_shadow_old) - determine_shadow(dpy, w); + determine_shadow(ps, w); } /** @@ -2311,29 +2130,29 @@ win_update_attr_shadow(Display *dpy, win *w) { * on shadow state. */ static void -determine_shadow(Display *dpy, win *w) { - Bool shadow_old = w->shadow; +determine_shadow(session_t *ps, win *w) { + bool shadow_old = w->shadow; - w->shadow = (opts.wintype_shadow[w->window_type] - && !win_match(w, opts.shadow_blacklist, &w->cache_sblst) - && !(opts.shadow_ignore_shaped && w->bounding_shaped + w->shadow = (ps->o.wintype_shadow[w->window_type] + && !win_match(w, ps->o.shadow_blacklist, &w->cache_sblst) + && !(ps->o.shadow_ignore_shaped && w->bounding_shaped && !w->rounded_corners) - && !(opts.respect_attr_shadow && 0 == w->attr_shadow)); + && !(ps->o.respect_prop_shadow && 0 == w->attr_shadow)); // Window extents need update on shadow state change if (w->shadow != shadow_old) { // Shadow geometry currently doesn't change on shadow state change - // calc_shadow_geometry(dpy, w); + // calc_shadow_geometry(ps, w); if (w->extents) { // Mark the old extents as damaged if the shadow is removed if (!w->shadow) - add_damage(dpy, w->extents); + add_damage(ps, w->extents); else - free_region(dpy, &w->extents); - w->extents = win_extents(dpy, w); + free_region(ps, &w->extents); + w->extents = win_extents(ps, w); // Mark the new extents as damaged if the shadow is added if (w->shadow) - add_damage_win(dpy, w); + add_damage_win(ps, w); } } } @@ -2343,10 +2162,10 @@ determine_shadow(Display *dpy, win *w) { */ static void -calc_win_size(Display *dpy, win *w) { +calc_win_size(session_t *ps, win *w) { w->widthb = w->a.width + w->a.border_width * 2; w->heightb = w->a.height + w->a.border_width * 2; - calc_shadow_geometry(dpy, w); + calc_shadow_geometry(ps, w); w->flags |= WFLAG_SIZE_CHANGE; } @@ -2354,11 +2173,11 @@ calc_win_size(Display *dpy, win *w) { * Calculate and update geometry of the shadow of a window. */ static void -calc_shadow_geometry(Display *dpy, win *w) { - w->shadow_dx = opts.shadow_offset_x; - w->shadow_dy = opts.shadow_offset_y; - w->shadow_width = w->widthb + gaussian_map->size; - w->shadow_height = w->heightb + gaussian_map->size; +calc_shadow_geometry(session_t *ps, win *w) { + w->shadow_dx = ps->o.shadow_offset_x; + w->shadow_dy = ps->o.shadow_offset_y; + w->shadow_width = w->widthb + ps->gaussian_map->size; + w->shadow_height = w->heightb + ps->gaussian_map->size; } /** @@ -2369,27 +2188,27 @@ calc_shadow_geometry(Display *dpy, win *w) { * @param client window ID of the client window */ static void -mark_client_win(Display *dpy, win *w, Window client) { +mark_client_win(session_t *ps, win *w, Window client) { w->client_win = client; - XSelectInput(dpy, client, determine_evmask(dpy, client, WIN_EVMODE_CLIENT)); + XSelectInput(ps->dpy, client, determine_evmask(ps, client, WIN_EVMODE_CLIENT)); // Get the frame width and monitor further frame width changes on client // window if necessary - if (opts.frame_opacity) { - get_frame_extents(dpy, w, client); + if (ps->o.frame_opacity) { + get_frame_extents(ps, w, client); } // Detect window type here if (WINTYPE_UNKNOWN == w->window_type) - w->window_type = get_wintype_prop(dpy, w->client_win); + w->window_type = wid_get_prop_wintype(ps, w->client_win); // Conform to EWMH standard, if _NET_WM_WINDOW_TYPE is not present, take // override-redirect windows or windows without WM_TRANSIENT_FOR as // _NET_WM_WINDOW_TYPE_NORMAL, otherwise as _NET_WM_WINDOW_TYPE_DIALOG. if (WINTYPE_UNKNOWN == w->window_type) { if (w->a.override_redirect - || !wid_has_attr(dpy, client, transient_atom)) + || !wid_has_attr(ps, client, ps->atom_transient)) w->window_type = WINTYPE_NORMAL; else w->window_type = WINTYPE_DIALOG; @@ -2397,8 +2216,9 @@ mark_client_win(Display *dpy, win *w, Window client) { } static void -add_win(Display *dpy, Window id, Window prev, Bool override_redirect) { - if (find_win(id)) { +add_win(session_t *ps, Window id, Window prev, bool override_redirect) { + // Reject overlay window and already added windows + if (id == ps->overlay || find_win(ps, id)) { return; } @@ -2408,24 +2228,24 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) { if (!new) return; if (prev) { - for (p = &list; *p; p = &(*p)->next) { + for (p = &ps->list; *p; p = &(*p)->next) { if ((*p)->id == prev && !(*p)->destroyed) break; } } else { - p = &list; + p = &ps->list; } new->id = id; - set_ignore(dpy, NextRequest(dpy)); + set_ignore_next(ps); - if (!XGetWindowAttributes(dpy, id, &new->a)) { + if (!XGetWindowAttributes(ps->dpy, id, &new->a)) { free(new); return; } new->damaged = 0; - new->to_paint = False; + new->to_paint = false; new->pixmap = None; new->picture = None; @@ -2433,9 +2253,9 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) { new->damage_sequence = 0; new->damage = None; } else { - new->damage_sequence = NextRequest(dpy); - set_ignore(dpy, NextRequest(dpy)); - new->damage = XDamageCreate(dpy, id, XDamageReportNonEmpty); + new->damage_sequence = NextRequest(ps->dpy); + set_ignore_next(ps); + new->damage = XDamageCreate(ps->dpy, id, XDamageReportNonEmpty); } new->name = NULL; @@ -2443,13 +2263,13 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) { new->class_general = NULL; new->cache_sblst = NULL; new->cache_fblst = NULL; - new->bounding_shaped = False; - new->rounded_corners = False; + new->bounding_shaped = false; + new->rounded_corners = false; new->border_size = None; new->reg_ignore = None; new->extents = None; - new->shadow = False; + new->shadow = false; new->shadow_opacity = 0.0; new->shadow_pict = None; new->shadow_alpha_pict = None; @@ -2461,15 +2281,15 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) { new->opacity_tgt = 0; new->opacity_prop = OPAQUE; new->opacity_prop_client = OPAQUE; - new->fade = False; + new->fade = false; new->fade_callback = NULL; new->alpha_pict = None; new->frame_opacity = 1.0; new->frame_alpha_pict = None; - new->dim = False; - new->focused = False; - new->destroyed = False; - new->need_configure = False; + new->dim = false; + new->focused = false; + new->destroyed = false; + new->need_configure = false; new->window_type = WINTYPE_UNKNOWN; new->mode = WINDOW_TRANS; new->attr_shadow = -1; @@ -2485,21 +2305,21 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) { new->flags = 0; - calc_win_size(dpy, new); + calc_win_size(ps, new); new->next = *p; *p = new; if (new->a.map_state == IsViewable) { - map_win(dpy, id, new->damage_sequence - 1, True, override_redirect); + map_win(ps, id, override_redirect); } } static void -restack_win(Display *dpy, win *w, Window new_above) { +restack_win(session_t *ps, win *w, Window new_above) { Window old_above; - update_reg_ignore_expire(w); + update_reg_ignore_expire(ps, w); if (w->next) { old_above = w->next->id; @@ -2511,14 +2331,14 @@ restack_win(Display *dpy, win *w, Window new_above) { win **prev; /* unhook */ - for (prev = &list; *prev; prev = &(*prev)->next) { + for (prev = &ps->list; *prev; prev = &(*prev)->next) { if ((*prev) == w) break; } *prev = w->next; /* rehook */ - for (prev = &list; *prev; prev = &(*prev)->next) { + for (prev = &ps->list; *prev; prev = &(*prev)->next) { if ((*prev)->id == new_above && !(*prev)->destroyed) break; } @@ -2531,7 +2351,7 @@ restack_win(Display *dpy, win *w, Window new_above) { const char *desc; char *window_name = NULL; bool to_free; - win* c = list; + win* c = ps->list; printf("restack_win(%#010lx, %#010lx): " "Window stack modified. Current stack:\n", w->id, new_above); @@ -2539,7 +2359,7 @@ restack_win(Display *dpy, win *w, Window new_above) { for (; c; c = c->next) { window_name = "(Failed to get title)"; - to_free = ev_window_name(dpy, c->id, &window_name); + to_free = ev_window_name(ps, c->id, &window_name); desc = ""; if (c->destroyed) desc = "(D) "; @@ -2557,21 +2377,21 @@ restack_win(Display *dpy, win *w, Window new_above) { } static void -configure_win(Display *dpy, XConfigureEvent *ce) { - if (ce->window == root) { - if (tgt_buffer) { - XRenderFreePicture(dpy, tgt_buffer); - tgt_buffer = None; +configure_win(session_t *ps, XConfigureEvent *ce) { + if (ce->window == ps->root) { + if (ps->tgt_buffer) { + XRenderFreePicture(ps->dpy, ps->tgt_buffer); + ps->tgt_buffer = None; } - root_width = ce->width; - root_height = ce->height; + ps->root_width = ce->width; + ps->root_height = ce->height; - rebuild_screen_reg(dpy); + rebuild_screen_reg(ps); return; } - win *w = find_win(ce->window); + win *w = find_win(ps, ce->window); XserverRegion damage = None; if (!w) @@ -2579,38 +2399,38 @@ configure_win(Display *dpy, XConfigureEvent *ce) { if (w->a.map_state == IsUnmapped) { /* save the configure event for when the window maps */ - w->need_configure = True; + w->need_configure = true; w->queue_configure = *ce; - restack_win(dpy, w, ce->above); + restack_win(ps, w, ce->above); } else { if (!(w->need_configure)) { - restack_win(dpy, w, ce->above); + restack_win(ps, w, ce->above); } // Windows restack (including window restacks happened when this // window is not mapped) could mess up all reg_ignore - reg_ignore_expire = True; + ps->reg_ignore_expire = true; - w->need_configure = False; + w->need_configure = false; - damage = XFixesCreateRegion(dpy, 0, 0); + damage = XFixesCreateRegion(ps->dpy, 0, 0); if (w->extents != None) { - XFixesCopyRegion(dpy, damage, w->extents); + XFixesCopyRegion(ps->dpy, damage, w->extents); } // If window geometry did not change, don't free extents here if (w->a.x != ce->x || w->a.y != ce->y || w->a.width != ce->width || w->a.height != ce->height) { - free_region(dpy, &w->extents); - free_region(dpy, &w->border_size); + free_region(ps, &w->extents); + free_region(ps, &w->border_size); } w->a.x = ce->x; w->a.y = ce->y; if (w->a.width != ce->width || w->a.height != ce->height) { - free_pixmap(dpy, &w->pixmap); - free_picture(dpy, &w->picture); + free_pixmap(ps, &w->pixmap); + free_picture(ps, &w->picture); } if (w->a.width != ce->width || w->a.height != ce->height @@ -2618,19 +2438,19 @@ configure_win(Display *dpy, XConfigureEvent *ce) { w->a.width = ce->width; w->a.height = ce->height; w->a.border_width = ce->border_width; - calc_win_size(dpy, w); + calc_win_size(ps, w); // Rounded corner detection is affected by window size - if (shape_exists && opts.shadow_ignore_shaped - && opts.detect_rounded_corners && w->bounding_shaped) - win_update_shape(dpy, w); + if (ps->shape_exists && ps->o.shadow_ignore_shaped + && ps->o.detect_rounded_corners && w->bounding_shaped) + win_update_shape(ps, w); } if (damage) { - XserverRegion extents = win_extents(dpy, w); - XFixesUnionRegion(dpy, damage, damage, extents); - XFixesDestroyRegion(dpy, extents); - add_damage(dpy, damage); + XserverRegion extents = win_extents(ps, w); + XFixesUnionRegion(ps->dpy, damage, damage, extents); + XFixesDestroyRegion(ps->dpy, extents); + add_damage(ps, damage); } } @@ -2638,40 +2458,35 @@ configure_win(Display *dpy, XConfigureEvent *ce) { } static void -circulate_win(Display *dpy, XCirculateEvent *ce) { - win *w = find_win(ce->window); +circulate_win(session_t *ps, XCirculateEvent *ce) { + win *w = find_win(ps, ce->window); Window new_above; if (!w) return; if (ce->place == PlaceOnTop) { - new_above = list->id; + new_above = ps->list->id; } else { new_above = None; } - restack_win(dpy, w, new_above); + restack_win(ps, w, new_above); } static void -finish_destroy_win(Display *dpy, Window id) { +finish_destroy_win(session_t *ps, Window id) { win **prev, *w; - for (prev = &list; (w = *prev); prev = &w->next) { + for (prev = &ps->list; (w = *prev); prev = &w->next) { if (w->id == id && w->destroyed) { - finish_unmap_win(dpy, w); + finish_unmap_win(ps, w); *prev = w->next; // Clear active_win if it's pointing to the destroyed window - if (active_win) - active_win = NULL; + if (ps->active_win) + ps->active_win = NULL; - free_picture(dpy, &w->shadow_pict); - free_damage(dpy, &w->damage); - free_region(dpy, &w->reg_ignore); - free(w->name); - free(w->class_instance); - free(w->class_general); + free_win_res(ps, w); free(w); break; @@ -2680,67 +2495,72 @@ finish_destroy_win(Display *dpy, Window id) { } static void -destroy_callback(Display *dpy, win *w) { - finish_destroy_win(dpy, w->id); +destroy_callback(session_t *ps, win *w) { + finish_destroy_win(ps, w->id); } static void -destroy_win(Display *dpy, Window id, Bool fade) { - win *w = find_win(id); +destroy_win(session_t *ps, Window id) { + win *w = find_win(ps, id); if (w) { - w->destroyed = True; + w->destroyed = true; // Fading out the window w->opacity_tgt = 0; - set_fade_callback(dpy, w, destroy_callback, False); + set_fade_callback(ps, w, destroy_callback, false); } } static inline void -root_damaged(void) { - if (root_tile) { - XClearArea(dpy, root, 0, 0, 0, 0, True); - // if (root_picture != root_tile) { - XRenderFreePicture(dpy, root_tile); - root_tile = None; +root_damaged(session_t *ps) { + if (ps->root_tile) { + XClearArea(ps->dpy, ps->root, 0, 0, 0, 0, true); + // if (ps->root_picture != ps->root_tile) { + XRenderFreePicture(ps->dpy, ps->root_tile); + ps->root_tile = None; /* } if (root_damage) { - XserverRegion parts = XFixesCreateRegion(dpy, 0, 0); - XDamageSubtract(dpy, root_damage, None, parts); - add_damage(dpy, parts); + XserverRegion parts = XFixesCreateRegion(ps->dpy, 0, 0); + XDamageSubtract(ps->dpy, root_damage, None, parts); + add_damage(ps, parts); } */ } // Mark screen damaged if we are painting on overlay - if (opts.paint_on_overlay) - add_damage(dpy, get_screen_region(dpy)); + if (ps->o.paint_on_overlay) + add_damage(ps, get_screen_region(ps)); } static void -damage_win(Display *dpy, XDamageNotifyEvent *de) { +damage_win(session_t *ps, XDamageNotifyEvent *de) { /* - if (root == de->drawable) { + if (ps->root == de->drawable) { root_damaged(); return; } */ - win *w = find_win(de->drawable); + win *w = find_win(ps, de->drawable); if (!w) return; - repair_win(dpy, w); + repair_win(ps, w); } +/** + * Xlib error handler function. + */ static int error(Display *dpy, XErrorEvent *ev) { + session_t * const ps = ps_g; + int o; const char *name = "Unknown"; - if (should_ignore(dpy, ev->serial)) { + if (should_ignore(ps, ev->serial)) { return 0; } - if (ev->request_code == composite_opcode + if (ev->request_code == ps->composite_opcode && ev->minor_code == X_CompositeRedirectSubwindows) { fprintf(stderr, "Another composite manager is already running\n"); exit(1); @@ -2748,17 +2568,17 @@ error(Display *dpy, XErrorEvent *ev) { #define CASESTRRET2(s) case s: name = #s; break - o = ev->error_code - xfixes_error; + o = ev->error_code - ps->xfixes_error; switch (o) { CASESTRRET2(BadRegion); } - o = ev->error_code - damage_error; + o = ev->error_code - ps->damage_error; switch (o) { CASESTRRET2(BadDamage); } - o = ev->error_code - render_error; + o = ev->error_code - ps->render_error; switch (o) { CASESTRRET2(BadPictFormat); CASESTRRET2(BadPicture); @@ -2789,7 +2609,7 @@ error(Display *dpy, XErrorEvent *ev) { #undef CASESTRRET2 - print_timestamp(); + print_timestamp(ps); printf("error %d (%s) request %d minor %d serial %lu\n", ev->error_code, name, ev->request_code, ev->minor_code, ev->serial); @@ -2798,74 +2618,84 @@ error(Display *dpy, XErrorEvent *ev) { } static void -expose_root(Display *dpy, XRectangle *rects, int nrects) { - XserverRegion region = XFixesCreateRegion(dpy, rects, nrects); - add_damage(dpy, region); +expose_root(session_t *ps, XRectangle *rects, int nrects) { + XserverRegion region = XFixesCreateRegion(ps->dpy, rects, nrects); + add_damage(ps, region); } -static Bool -wid_get_text_prop(Display *dpy, Window wid, Atom prop, +/** + * Get the value of a text property of a window. + */ +static bool +wid_get_text_prop(session_t *ps, Window wid, Atom prop, char ***pstrlst, int *pnstr) { XTextProperty text_prop; - if (!(XGetTextProperty(dpy, wid, &text_prop, prop) && text_prop.value)) - return False; + if (!(XGetTextProperty(ps->dpy, wid, &text_prop, prop) && text_prop.value)) + return false; if (Success != - XmbTextPropertyToTextList(dpy, &text_prop, pstrlst, pnstr) + XmbTextPropertyToTextList(ps->dpy, &text_prop, pstrlst, pnstr) || !*pnstr) { *pnstr = 0; if (*pstrlst) XFreeStringList(*pstrlst); - return False; + return false; } - return True; + return true; } -static Bool -wid_get_name(Display *dpy, Window wid, char **name) { +/** + * Get the name of a window from window ID. + */ +static bool +wid_get_name(session_t *ps, Window wid, char **name) { XTextProperty text_prop; char **strlst = NULL; int nstr = 0; - // set_ignore(dpy, NextRequest(dpy)); - if (!(XGetTextProperty(dpy, wid, &text_prop, name_ewmh_atom) + // set_ignore_next(ps); + if (!(XGetTextProperty(ps->dpy, wid, &text_prop, ps->atom_name_ewmh) && text_prop.value)) { - // set_ignore(dpy, NextRequest(dpy)); + // set_ignore_next(ps); #ifdef DEBUG_WINDATA printf("wid_get_name(%#010lx): _NET_WM_NAME unset, falling back to WM_NAME.\n", wid); #endif - if (!(XGetWMName(dpy, wid, &text_prop) && text_prop.value)) { - return False; + if (!(XGetWMName(ps->dpy, wid, &text_prop) && text_prop.value)) { + return false; } } if (Success != - XmbTextPropertyToTextList(dpy, &text_prop, &strlst, &nstr) + XmbTextPropertyToTextList(ps->dpy, &text_prop, &strlst, &nstr) || !nstr || !strlst) { if (strlst) XFreeStringList(strlst); - return False; + return false; } *name = mstrcpy(strlst[0]); XFreeStringList(strlst); - return True; + return true; } +/** + * Retrieve the name of a window and update its win + * structure. + */ static int -win_get_name(Display *dpy, win *w) { - Bool ret; +win_get_name(session_t *ps, win *w) { + bool ret; char *name_old = w->name; // Can't do anything if there's no client window if (!w->client_win) - return False; + return false; // Get the name - ret = wid_get_name(dpy, w->client_win, &w->name); + ret = wid_get_name(ps, w->client_win, &w->name); // Return -1 if wid_get_name() failed, 0 if name didn't change, 1 if // it changes @@ -2888,14 +2718,18 @@ win_get_name(Display *dpy, win *w) { return ret; } -static Bool -win_get_class(Display *dpy, win *w) { +/** + * Retrieve the WM_CLASS of a window and update its + * win structure. + */ +static bool +win_get_class(session_t *ps, win *w) { char **strlst = NULL; int nstr = 0; // Can't do anything if there's no client window if (!w->client_win) - return False; + return false; // Free and reset old strings free(w->class_instance); @@ -2904,8 +2738,8 @@ win_get_class(Display *dpy, win *w) { w->class_general = NULL; // Retrieve the property string list - if (!wid_get_text_prop(dpy, w->client_win, class_atom, &strlst, &nstr)) - return False; + if (!wid_get_text_prop(ps, w->client_win, ps->atom_class, &strlst, &nstr)) + return false; // Copy the strings if successful w->class_instance = mstrcpy(strlst[0]); @@ -2921,7 +2755,7 @@ win_get_class(Display *dpy, win *w) { w->id, w->client_win, w->class_instance, w->class_general); #endif - return True; + return true; } #ifdef DEBUG_EVENTS @@ -2934,7 +2768,7 @@ ev_serial(XEvent *ev) { } static const char * -ev_name(XEvent *ev) { +ev_name(session_t *ps, XEvent *ev) { static char buf[128]; switch (ev->type & 0x7f) { CASESTRRET(FocusIn); @@ -2950,11 +2784,11 @@ ev_name(XEvent *ev) { CASESTRRET(PropertyNotify); CASESTRRET(ClientMessage); default: - if (ev->type == damage_event + XDamageNotify) { + if (ev->type == ps->damage_event + XDamageNotify) { return "Damage"; } - if (shape_exists && ev->type == shape_event) { + if (ps->shape_exists && ev->type == ps->shape_event) { return "ShapeNotify"; } @@ -2965,7 +2799,7 @@ ev_name(XEvent *ev) { } static Window -ev_window(XEvent *ev) { +ev_window(session_t *ps, XEvent *ev) { switch (ev->type) { case FocusIn: case FocusOut: @@ -2991,11 +2825,11 @@ ev_window(XEvent *ev) { case ClientMessage: return ev->xclient.window; default: - if (ev->type == damage_event + XDamageNotify) { + if (ev->type == ps->damage_event + XDamageNotify) { return ((XDamageNotifyEvent *)ev)->drawable; } - if (shape_exists && ev->type == shape_event) { + if (ps->shape_exists && ev->type == ps->shape_event) { return ((XShapeEvent *) ev)->window; } @@ -3039,9 +2873,7 @@ ev_focus_report(XFocusChangeEvent* ev) { #endif -/** - * Events - */ +// === Events === /** * Determine whether we should respond to a FocusIn/Out @@ -3054,7 +2886,7 @@ ev_focus_accept(XFocusChangeEvent *ev) { } inline static void -ev_focus_in(XFocusChangeEvent *ev) { +ev_focus_in(session_t *ps, XFocusChangeEvent *ev) { #ifdef DEBUG_EVENTS ev_focus_report(ev); #endif @@ -3062,16 +2894,16 @@ ev_focus_in(XFocusChangeEvent *ev) { if (!ev_focus_accept(ev)) return; - win *w = find_win(ev->window); + win *w = find_win(ps, ev->window); // To deal with events sent from windows just destroyed if (!w) return; - set_focused(dpy, w, True); + set_focused(ps, w, true); } inline static void -ev_focus_out(XFocusChangeEvent *ev) { +ev_focus_out(session_t *ps, XFocusChangeEvent *ev) { #ifdef DEBUG_EVENTS ev_focus_report(ev); #endif @@ -3079,93 +2911,93 @@ ev_focus_out(XFocusChangeEvent *ev) { if (!ev_focus_accept(ev)) return; - win *w = find_win(ev->window); + win *w = find_win(ps, ev->window); // To deal with events sent from windows just destroyed if (!w) return; - set_focused(dpy, w, False); + set_focused(ps, w, false); } inline static void -ev_create_notify(XCreateWindowEvent *ev) { - assert(ev->parent == root); - add_win(dpy, ev->window, 0, ev->override_redirect); +ev_create_notify(session_t *ps, XCreateWindowEvent *ev) { + assert(ev->parent == ps->root); + add_win(ps, ev->window, 0, ev->override_redirect); } inline static void -ev_configure_notify(XConfigureEvent *ev) { +ev_configure_notify(session_t *ps, XConfigureEvent *ev) { #ifdef DEBUG_EVENTS printf(" { send_event: %d, " " above: %#010lx, " " override_redirect: %d }\n", ev->send_event, ev->above, ev->override_redirect); #endif - configure_win(dpy, ev); + configure_win(ps, ev); } inline static void -ev_destroy_notify(XDestroyWindowEvent *ev) { - destroy_win(dpy, ev->window, True); +ev_destroy_notify(session_t *ps, XDestroyWindowEvent *ev) { + destroy_win(ps, ev->window); } inline static void -ev_map_notify(XMapEvent *ev) { - map_win(dpy, ev->window, ev->serial, True, ev->override_redirect); +ev_map_notify(session_t *ps, XMapEvent *ev) { + map_win(ps, ev->window, ev->override_redirect); } inline static void -ev_unmap_notify(XUnmapEvent *ev) { - unmap_win(dpy, ev->window, True); +ev_unmap_notify(session_t *ps, XUnmapEvent *ev) { + unmap_win(ps, ev->window); } inline static void -ev_reparent_notify(XReparentEvent *ev) { - if (ev->parent == root) { - add_win(dpy, ev->window, 0, ev->override_redirect); +ev_reparent_notify(session_t *ps, XReparentEvent *ev) { + if (ev->parent == ps->root) { + add_win(ps, ev->window, 0, ev->override_redirect); } else { - destroy_win(dpy, ev->window, True); + destroy_win(ps, ev->window); // Reset event mask in case something wrong happens - XSelectInput(dpy, ev->window, - determine_evmask(dpy, ev->window, WIN_EVMODE_UNKNOWN)); + XSelectInput(ps->dpy, ev->window, + determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN)); /* // Check if the window is a client window of another - win *w_top = find_toplevel2(dpy, ev->window); + win *w_top = find_toplevel2(ps, ev->window); if (w_top && !(w_top->client_win)) { - mark_client_win(dpy, w_top, ev->window); + mark_client_win(ps, w_top, ev->window); } */ } } inline static void -ev_circulate_notify(XCirculateEvent *ev) { - circulate_win(dpy, ev); +ev_circulate_notify(session_t *ps, XCirculateEvent *ev) { + circulate_win(ps, ev); } inline static void -ev_expose(XExposeEvent *ev) { - if (ev->window == root || (overlay && ev->window == overlay)) { +ev_expose(session_t *ps, XExposeEvent *ev) { + if (ev->window == ps->root || (ps->overlay && ev->window == ps->overlay)) { int more = ev->count + 1; - if (n_expose == size_expose) { - if (expose_rects) { - expose_rects = realloc(expose_rects, - (size_expose + more) * sizeof(XRectangle)); - size_expose += more; + if (ps->n_expose == ps->size_expose) { + if (ps->expose_rects) { + ps->expose_rects = realloc(ps->expose_rects, + (ps->size_expose + more) * sizeof(XRectangle)); + ps->size_expose += more; } else { - expose_rects = malloc(more * sizeof(XRectangle)); - size_expose = more; + ps->expose_rects = malloc(more * sizeof(XRectangle)); + ps->size_expose = more; } } - expose_rects[n_expose].x = ev->x; - expose_rects[n_expose].y = ev->y; - expose_rects[n_expose].width = ev->width; - expose_rects[n_expose].height = ev->height; - n_expose++; + ps->expose_rects[ps->n_expose].x = ev->x; + ps->expose_rects[ps->n_expose].y = ev->y; + ps->expose_rects[ps->n_expose].width = ev->width; + ps->expose_rects[ps->n_expose].height = ev->height; + ps->n_expose++; if (ev->count == 0) { - expose_root(dpy, expose_rects, n_expose); - n_expose = 0; + expose_root(ps, ps->expose_rects, ps->n_expose); + ps->n_expose = 0; } } } @@ -3177,46 +3009,47 @@ ev_expose(XExposeEvent *ev) { * returned could not be found. */ static void -update_ewmh_active_win(Display *dpy) { +update_ewmh_active_win(session_t *ps) { // Get the attribute firstly - winattr_t attr = wid_get_attr(dpy, root, ewmh_active_win_atom, + winprop_t prop = wid_get_prop(ps, ps->root, ps->atom_ewmh_active_win, 1L, XA_WINDOW, 32); - if (!attr.nitems) { - free_winattr(&attr); + if (!prop.nitems) { + free_winprop(&prop); return; } - - // Search for the window - Window wid = *((long *) attr.data); - win *w = NULL; - free_winattr(&attr); - if (!(w = find_toplevel(wid))) - if (!(w = find_win(wid))) - w = find_toplevel2(dpy, wid); + // Search for the window + Window wid = *((long *) prop.data); + win *w = NULL; + free_winprop(&prop); + + if (!(w = find_toplevel(ps, wid))) + if (!(w = find_win(ps, wid))) + w = find_toplevel2(ps, wid); // Mark the window focused if (w) { if (!w->focused) - set_focused(dpy, w, True); - if (active_win && w != active_win) - set_focused(dpy, active_win, False); - active_win = w; + set_focused(ps, w, true); + if (ps->active_win && w != ps->active_win) + set_focused(ps, ps->active_win, false); + ps->active_win = w; } } inline static void -ev_property_notify(XPropertyEvent *ev) { - if (root == ev->window) { - if (opts.track_focus && opts.use_ewmh_active_win - && ewmh_active_win_atom == ev->atom) { - update_ewmh_active_win(dpy); +ev_property_notify(session_t *ps, XPropertyEvent *ev) { + if (ps->root == ev->window) { + if (ps->o.track_focus && ps->o.use_ewmh_active_win + && ps->atom_ewmh_active_win == ev->atom) { + update_ewmh_active_win(ps); } else { // Destroy the root "image" if the wallpaper probably changed - for (int p = 0; background_props[p]; p++) { - if (ev->atom == XInternAtom(dpy, background_props[p], False)) { - root_damaged(); + for (int p = 0; background_props_str[p]; p++) { + if (ev->atom == + XInternAtom(ps->dpy, background_props_str[p], false)) { + root_damaged(ps); break; } } @@ -3227,62 +3060,62 @@ ev_property_notify(XPropertyEvent *ev) { } // If _NET_WM_OPACITY changes - if (ev->atom == opacity_atom) { + if (ev->atom == ps->atom_opacity) { win *w = NULL; - if ((w = find_win(ev->window))) - w->opacity_prop = wid_get_opacity_prop(dpy, w->id, OPAQUE); - else if (opts.detect_client_opacity - && (w = find_toplevel(ev->window))) - w->opacity_prop_client = wid_get_opacity_prop(dpy, w->client_win, + if ((w = find_win(ps, ev->window))) + w->opacity_prop = wid_get_opacity_prop(ps, w->id, OPAQUE); + else if (ps->o.detect_client_opacity + && (w = find_toplevel(ps, ev->window))) + w->opacity_prop_client = wid_get_opacity_prop(ps, w->client_win, OPAQUE); if (w) { - calc_opacity(dpy, w, False); + calc_opacity(ps, w, false); } } // If frame extents property changes - if (opts.frame_opacity && ev->atom == frame_extents_atom) { - win *w = find_toplevel(ev->window); + if (ps->o.frame_opacity && ev->atom == ps->atom_frame_extents) { + win *w = find_toplevel(ps, ev->window); if (w) { - get_frame_extents(dpy, w, ev->window); + get_frame_extents(ps, w, ev->window); // If frame extents change, the window needs repaint - add_damage_win(dpy, w); + add_damage_win(ps, w); } } // If name changes - if (opts.track_wdata - && (name_atom == ev->atom || name_ewmh_atom == ev->atom)) { - win *w = find_toplevel(ev->window); - if (w && 1 == win_get_name(dpy, w)) - determine_shadow(dpy, w); + if (ps->o.track_wdata + && (ps->atom_name == ev->atom || ps->atom_name_ewmh == ev->atom)) { + win *w = find_toplevel(ps, ev->window); + if (w && 1 == win_get_name(ps, w)) + determine_shadow(ps, w); } // If class changes - if (opts.track_wdata && class_atom == ev->atom) { - win *w = find_toplevel(ev->window); + if (ps->o.track_wdata && ps->atom_class == ev->atom) { + win *w = find_toplevel(ps, ev->window); if (w) { - win_get_class(dpy, w); - determine_shadow(dpy, w); + win_get_class(ps, w); + determine_shadow(ps, w); } } // If _COMPTON_SHADOW changes - if (opts.respect_attr_shadow && compton_shadow_atom == ev->atom) { - win *w = find_win(ev->window); + if (ps->o.respect_prop_shadow && ps->atom_compton_shadow == ev->atom) { + win *w = find_win(ps, ev->window); if (w) - win_update_attr_shadow(dpy, w); + win_update_attr_shadow(ps, w); } } inline static void -ev_damage_notify(XDamageNotifyEvent *ev) { - damage_win(dpy, ev); +ev_damage_notify(session_t *ps, XDamageNotifyEvent *ev) { + damage_win(ps, ev); } inline static void -ev_shape_notify(XShapeEvent *ev) { - win *w = find_win(ev->window); +ev_shape_notify(session_t *ps, XShapeEvent *ev) { + win *w = find_win(ps, ev->window); if (!w || IsUnmapped == w->a.map_state) return; /* @@ -3293,31 +3126,31 @@ ev_shape_notify(XShapeEvent *ev) { */ if (w->border_size) { // Mark the old border_size as damaged - add_damage(dpy, w->border_size); + add_damage(ps, w->border_size); - w->border_size = border_size(dpy, w); + w->border_size = border_size(ps, w); // Mark the new border_size as damaged - add_damage(dpy, copy_region(dpy, w->border_size)); + add_damage(ps, copy_region(ps, w->border_size)); } // Redo bounding shape detection and rounded corner detection - win_update_shape(dpy, w); + win_update_shape(ps, w); - update_reg_ignore_expire(w); + update_reg_ignore_expire(ps, w); } /** * Handle ScreenChangeNotify events from X RandR extension. */ static void -ev_screen_change_notify(XRRScreenChangeNotifyEvent *ev) { - if (!opts.refresh_rate) { - update_refresh_rate(dpy); - if (!refresh_rate) { +ev_screen_change_notify(session_t *ps, XRRScreenChangeNotifyEvent *ev) { + if (!ps->o.refresh_rate) { + update_refresh_rate(ps); + if (!ps->refresh_rate) { fprintf(stderr, "ev_screen_change_notify(): Refresh rate detection " "failed, software VSync disabled."); - opts.vsync = VSYNC_NONE; + ps->o.vsync = VSYNC_NONE; } } } @@ -3327,26 +3160,26 @@ ev_screen_change_notify(XRRScreenChangeNotifyEvent *ev) { * Get a window's name from window ID. */ static bool -ev_window_name(Display *dpy, Window wid, char **name) { +ev_window_name(session_t *ps, Window wid, char **name) { bool to_free = false; *name = ""; if (wid) { *name = "(Failed to get title)"; - if (root == wid) + if (ps->root == wid) *name = "(Root window)"; - else if (overlay == wid) + else if (ps->overlay == wid) *name = "(Overlay)"; else { - win *w = find_win(wid); + win *w = find_win(ps, wid); if (!w) - w = find_toplevel(wid); + w = find_toplevel(ps, wid); if (w && w->name) *name = w->name; else if (!(w && w->client_win - && (to_free = wid_get_name(dpy, w->client_win, name)))) - to_free = wid_get_name(dpy, wid, name); + && (to_free = wid_get_name(ps, w->client_win, name)))) + to_free = wid_get_name(ps, wid, name); } } @@ -3355,22 +3188,22 @@ ev_window_name(Display *dpy, Window wid, char **name) { #endif static void -ev_handle(XEvent *ev) { +ev_handle(session_t *ps, XEvent *ev) { if ((ev->type & 0x7f) != KeymapNotify) { - discard_ignore(dpy, ev->xany.serial); + discard_ignore(ps, ev->xany.serial); } #ifdef DEBUG_EVENTS - if (ev->type != damage_event + XDamageNotify) { - Window wid = ev_window(ev); + if (ev->type != ps->damage_event + XDamageNotify) { + Window wid = ev_window(ps, ev); char *window_name = NULL; - Bool to_free = false; + bool to_free = false; - to_free = ev_window_name(dpy, wid, &window_name); + to_free = ev_window_name(ps, wid, &window_name); - print_timestamp(); + print_timestamp(ps); printf("event %10.10s serial %#010x window %#010lx \"%s\"\n", - ev_name(ev), ev_serial(ev), wid, window_name); + ev_name(ps, ev), ev_serial(ev), wid, window_name); if (to_free) { XFree(window_name); @@ -3382,57 +3215,55 @@ ev_handle(XEvent *ev) { switch (ev->type) { case FocusIn: - ev_focus_in((XFocusChangeEvent *)ev); + ev_focus_in(ps, (XFocusChangeEvent *)ev); break; case FocusOut: - ev_focus_out((XFocusChangeEvent *)ev); + ev_focus_out(ps, (XFocusChangeEvent *)ev); break; case CreateNotify: - ev_create_notify((XCreateWindowEvent *)ev); + ev_create_notify(ps, (XCreateWindowEvent *)ev); break; case ConfigureNotify: - ev_configure_notify((XConfigureEvent *)ev); + ev_configure_notify(ps, (XConfigureEvent *)ev); break; case DestroyNotify: - ev_destroy_notify((XDestroyWindowEvent *)ev); + ev_destroy_notify(ps, (XDestroyWindowEvent *)ev); break; case MapNotify: - ev_map_notify((XMapEvent *)ev); + ev_map_notify(ps, (XMapEvent *)ev); break; case UnmapNotify: - ev_unmap_notify((XUnmapEvent *)ev); + ev_unmap_notify(ps, (XUnmapEvent *)ev); break; case ReparentNotify: - ev_reparent_notify((XReparentEvent *)ev); + ev_reparent_notify(ps, (XReparentEvent *)ev); break; case CirculateNotify: - ev_circulate_notify((XCirculateEvent *)ev); + ev_circulate_notify(ps, (XCirculateEvent *)ev); break; case Expose: - ev_expose((XExposeEvent *)ev); + ev_expose(ps, (XExposeEvent *)ev); break; case PropertyNotify: - ev_property_notify((XPropertyEvent *)ev); + ev_property_notify(ps, (XPropertyEvent *)ev); break; default: - if (shape_exists && ev->type == shape_event) { - ev_shape_notify((XShapeEvent *) ev); + if (ps->shape_exists && ev->type == ps->shape_event) { + ev_shape_notify(ps, (XShapeEvent *) ev); break; } - if (randr_exists && ev->type == (randr_event + RRScreenChangeNotify)) { - ev_screen_change_notify((XRRScreenChangeNotifyEvent *) ev); + if (ps->randr_exists && ev->type == (ps->randr_event + RRScreenChangeNotify)) { + ev_screen_change_notify(ps, (XRRScreenChangeNotifyEvent *) ev); break; } - if (ev->type == damage_event + XDamageNotify) { - ev_damage_notify((XDamageNotifyEvent *)ev); + if (ev->type == ps->damage_event + XDamageNotify) { + ev_damage_notify(ps, (XDamageNotifyEvent *)ev); } break; } } -/** - * Main - */ +// === Main === /** * Print usage text and exit. @@ -3541,7 +3372,7 @@ usage(void) { "--use-ewmh-active-win\n" " Use _NET_WM_ACTIVE_WINDOW on the root window to determine which\n" " window is focused instead of using FocusIn/Out events.\n" - "--respect-attr-shadow\n" + "--respect-prop-shadow\n" " Respect _COMPTON_SHADOW. This a prototype-level feature, which\n" " you must not rely on.\n" "--unredir-if-possible\n" @@ -3573,7 +3404,7 @@ usage(void) { * Register a window as symbol, and initialize GLX context if wanted. */ static void -register_cm(Bool want_glxct) { +register_cm(session_t *ps, bool want_glxct) { Atom a; char *buf; int len, s; @@ -3582,10 +3413,10 @@ register_cm(Bool want_glxct) { // Create a window with the wanted GLX visual if (want_glxct) { XVisualInfo *pvi = NULL; - Bool ret = False; + bool ret = false; // Get visual for the window int attribs[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, None }; - pvi = glXChooseVisual(dpy, scr, attribs); + pvi = glXChooseVisual(ps->dpy, ps->scr, attribs); if (!pvi) { fprintf(stderr, "register_cm(): Failed to choose visual required " @@ -3594,28 +3425,28 @@ register_cm(Bool want_glxct) { else { // Create the window XSetWindowAttributes swa = { - .colormap = XCreateColormap(dpy, root, pvi->visual, AllocNone), + .colormap = XCreateColormap(ps->dpy, ps->root, pvi->visual, AllocNone), .border_pixel = 0, }; - pvi->screen = scr; - reg_win = XCreateWindow(dpy, root, 0, 0, 1, 1, 0, pvi->depth, + pvi->screen = ps->scr; + ps->reg_win = XCreateWindow(ps->dpy, ps->root, 0, 0, 1, 1, 0, pvi->depth, InputOutput, pvi->visual, CWBorderPixel | CWColormap, &swa); - if (!reg_win) + if (!ps->reg_win) fprintf(stderr, "register_cm(): Failed to create window required " "by fake OpenGL VSync. OpenGL VSync turned off.\n"); else { // Get GLX context - glx_context = glXCreateContext(dpy, pvi, None, GL_TRUE); - if (!glx_context) { + ps->glx_context = glXCreateContext(ps->dpy, pvi, None, GL_TRUE); + if (!ps->glx_context) { fprintf(stderr, "register_cm(): Failed to get GLX context. " "OpenGL VSync turned off.\n"); - opts.vsync = VSYNC_NONE; + ps->o.vsync = VSYNC_NONE; } else { // Attach GLX context - if (!(ret = glXMakeCurrent(dpy, reg_win, glx_context))) + if (!(ret = glXMakeCurrent(ps->dpy, ps->reg_win, ps->glx_context))) fprintf(stderr, "register_cm(): Failed to attach GLX context." " OpenGL VSync turned off.\n"); } @@ -3625,20 +3456,19 @@ register_cm(Bool want_glxct) { XFree(pvi); if (!ret) - opts.vsync = VSYNC_NONE; + ps->o.vsync = VSYNC_NONE; } #endif - - if (!reg_win) - reg_win = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, + + if (!ps->reg_win) + ps->reg_win = XCreateSimpleWindow(ps->dpy, ps->root, 0, 0, 1, 1, 0, None, None); - Xutf8SetWMProperties( - dpy, reg_win, "xcompmgr", "xcompmgr", + Xutf8SetWMProperties(ps->dpy, ps->reg_win, "xcompmgr", "xcompmgr", NULL, 0, NULL, NULL, NULL); len = strlen(REGISTER_PROP) + 2; - s = scr; + s = ps->scr; while (s >= 10) { ++len; @@ -3646,14 +3476,17 @@ register_cm(Bool want_glxct) { } buf = malloc(len); - snprintf(buf, len, REGISTER_PROP"%d", scr); + snprintf(buf, len, REGISTER_PROP"%d", ps->scr); - a = XInternAtom(dpy, buf, False); + a = XInternAtom(ps->dpy, buf, false); free(buf); - XSetSelectionOwner(dpy, a, reg_win, 0); + XSetSelectionOwner(ps->dpy, a, ps->reg_win, 0); } +/** + * Fork program to background and disable all I/O streams. + */ static void fork_after(void) { if (getppid() == 1) return; @@ -3769,7 +3602,7 @@ open_config_file(char *cpath, char **ppath) { * Parse a VSync option argument. */ static inline void -parse_vsync(const char *optarg) { +parse_vsync(session_t *ps, const char *optarg) { const static char * const vsync_str[] = { "none", // VSYNC_NONE "drm", // VSYNC_DRM @@ -3780,7 +3613,7 @@ parse_vsync(const char *optarg) { for (i = 0; i < (sizeof(vsync_str) / sizeof(vsync_str[0])); ++i) if (!strcasecmp(optarg, vsync_str[i])) { - opts.vsync = i; + ps->o.vsync = i; break; } if ((sizeof(vsync_str) / sizeof(vsync_str[0])) == i) { @@ -3792,7 +3625,7 @@ parse_vsync(const char *optarg) { * Parse a configuration file from default location. */ static void -parse_config(char *cpath, struct options_tmp *pcfgtmp) { +parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp) { char *path = NULL; FILE *f; config_t cfg; @@ -3830,31 +3663,31 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) { // -D (fade_delta) if (lcfg_lookup_int(&cfg, "fade-delta", &ival)) - opts.fade_delta = ival; + ps->o.fade_delta = ival; // -I (fade_in_step) if (config_lookup_float(&cfg, "fade-in-step", &dval)) - opts.fade_in_step = normalize_d(dval) * OPAQUE; + ps->o.fade_in_step = normalize_d(dval) * OPAQUE; // -O (fade_out_step) if (config_lookup_float(&cfg, "fade-out-step", &dval)) - opts.fade_out_step = normalize_d(dval) * OPAQUE; + ps->o.fade_out_step = normalize_d(dval) * OPAQUE; // -r (shadow_radius) - lcfg_lookup_int(&cfg, "shadow-radius", &opts.shadow_radius); + lcfg_lookup_int(&cfg, "shadow-radius", &ps->o.shadow_radius); // -o (shadow_opacity) - config_lookup_float(&cfg, "shadow-opacity", &opts.shadow_opacity); + config_lookup_float(&cfg, "shadow-opacity", &ps->o.shadow_opacity); // -l (shadow_offset_x) - lcfg_lookup_int(&cfg, "shadow-offset-x", &opts.shadow_offset_x); + lcfg_lookup_int(&cfg, "shadow-offset-x", &ps->o.shadow_offset_x); // -t (shadow_offset_y) - lcfg_lookup_int(&cfg, "shadow-offset-y", &opts.shadow_offset_y); + lcfg_lookup_int(&cfg, "shadow-offset-y", &ps->o.shadow_offset_y); // -i (inactive_opacity) if (config_lookup_float(&cfg, "inactive-opacity", &dval)) - opts.inactive_opacity = normalize_d(dval) * OPAQUE; + ps->o.inactive_opacity = normalize_d(dval) * OPAQUE; // -e (frame_opacity) - config_lookup_float(&cfg, "frame-opacity", &opts.frame_opacity); + config_lookup_float(&cfg, "frame-opacity", &ps->o.frame_opacity); // -z (clear_shadow) - lcfg_lookup_bool(&cfg, "clear-shadow", &opts.clear_shadow); + lcfg_lookup_bool(&cfg, "clear-shadow", &ps->o.clear_shadow); // -c (shadow_enable) if (config_lookup_bool(&cfg, "shadow", &ival) && ival) - wintype_arr_enable(opts.wintype_shadow); + wintype_arr_enable(ps->o.wintype_shadow); // -C (no_dock_shadow) lcfg_lookup_bool(&cfg, "no-dock-shadow", &pcfgtmp->no_dock_shadow); // -G (no_dnd_shadow) @@ -3863,53 +3696,53 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) { config_lookup_float(&cfg, "menu-opacity", &pcfgtmp->menu_opacity); // -f (fading_enable) if (config_lookup_bool(&cfg, "fading", &ival) && ival) - wintype_arr_enable(opts.wintype_fade); + wintype_arr_enable(ps->o.wintype_fade); // --no-fading-open-close - lcfg_lookup_bool(&cfg, "no-fading-openclose", &opts.no_fading_openclose); + lcfg_lookup_bool(&cfg, "no-fading-openclose", &ps->o.no_fading_openclose); // --shadow-red - config_lookup_float(&cfg, "shadow-red", &opts.shadow_red); + config_lookup_float(&cfg, "shadow-red", &ps->o.shadow_red); // --shadow-green - config_lookup_float(&cfg, "shadow-green", &opts.shadow_green); + config_lookup_float(&cfg, "shadow-green", &ps->o.shadow_green); // --shadow-blue - config_lookup_float(&cfg, "shadow-blue", &opts.shadow_blue); + config_lookup_float(&cfg, "shadow-blue", &ps->o.shadow_blue); // --inactive-opacity-override lcfg_lookup_bool(&cfg, "inactive-opacity-override", - &opts.inactive_opacity_override); + &ps->o.inactive_opacity_override); // --inactive-dim - config_lookup_float(&cfg, "inactive-dim", &opts.inactive_dim); + config_lookup_float(&cfg, "inactive-dim", &ps->o.inactive_dim); // --mark-wmwin-focused - lcfg_lookup_bool(&cfg, "mark-wmwin-focused", &opts.mark_wmwin_focused); + lcfg_lookup_bool(&cfg, "mark-wmwin-focused", &ps->o.mark_wmwin_focused); // --mark-ovredir-focused lcfg_lookup_bool(&cfg, "mark-ovredir-focused", - &opts.mark_ovredir_focused); + &ps->o.mark_ovredir_focused); // --shadow-ignore-shaped lcfg_lookup_bool(&cfg, "shadow-ignore-shaped", - &opts.shadow_ignore_shaped); + &ps->o.shadow_ignore_shaped); // --detect-rounded-corners lcfg_lookup_bool(&cfg, "detect-rounded-corners", - &opts.detect_rounded_corners); + &ps->o.detect_rounded_corners); // --detect-client-opacity lcfg_lookup_bool(&cfg, "detect-client-opacity", - &opts.detect_client_opacity); + &ps->o.detect_client_opacity); // --refresh-rate - lcfg_lookup_int(&cfg, "refresh-rate", &opts.refresh_rate); + lcfg_lookup_int(&cfg, "refresh-rate", &ps->o.refresh_rate); // --vsync if (config_lookup_string(&cfg, "vsync", &sval)) - parse_vsync(sval); + parse_vsync(ps, sval); // --alpha-step - config_lookup_float(&cfg, "alpha-step", &opts.alpha_step); + config_lookup_float(&cfg, "alpha-step", &ps->o.alpha_step); // --dbe - lcfg_lookup_bool(&cfg, "dbe", &opts.dbe); + lcfg_lookup_bool(&cfg, "dbe", &ps->o.dbe); // --paint-on-overlay - lcfg_lookup_bool(&cfg, "paint-on-overlay", &opts.paint_on_overlay); + lcfg_lookup_bool(&cfg, "paint-on-overlay", &ps->o.paint_on_overlay); // --sw-opti - lcfg_lookup_bool(&cfg, "sw-opti", &opts.sw_opti); + lcfg_lookup_bool(&cfg, "sw-opti", &ps->o.sw_opti); // --use-ewmh-active-win lcfg_lookup_bool(&cfg, "use-ewmh-active-win", - &opts.use_ewmh_active_win); + &ps->o.use_ewmh_active_win); // --unredir-if-possible lcfg_lookup_bool(&cfg, "unredir-if-possible", - &opts.unredir_if_possible); + &ps->o.unredir_if_possible); // --shadow-exclude { config_setting_t *setting = @@ -3919,20 +3752,20 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) { if (config_setting_is_array(setting)) { int i = config_setting_length(setting); while (i--) { - condlst_add(&opts.shadow_blacklist, + condlst_add(&ps->o.shadow_blacklist, config_setting_get_string_elem(setting, i)); } } // Treat it as a single pattern if it's a string else if (CONFIG_TYPE_STRING == config_setting_type(setting)) { - condlst_add(&opts.shadow_blacklist, + condlst_add(&ps->o.shadow_blacklist, config_setting_get_string(setting)); } } } // Wintype settings { - wintype i; + wintype_t i; for (i = 0; i < NUM_WINTYPES; ++i) { char *str = mstrjoin("wintypes.", WINTYPES[i]); @@ -3940,11 +3773,11 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) { free(str); if (setting) { if (config_setting_lookup_bool(setting, "shadow", &ival)) - opts.wintype_shadow[i] = (Bool) ival; + ps->o.wintype_shadow[i] = (bool) ival; if (config_setting_lookup_bool(setting, "fade", &ival)) - opts.wintype_fade[i] = (Bool) ival; + ps->o.wintype_fade[i] = (bool) ival; config_setting_lookup_float(setting, "opacity", - &opts.wintype_opacity[i]); + &ps->o.wintype_opacity[i]); } } } @@ -3957,7 +3790,7 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) { * Process arguments and configuration files. */ static void -get_cfg(int argc, char *const *argv) { +get_cfg(session_t *ps, int argc, char *const *argv) { const static char *shortopts = "D:I:O:d:r:o:m:l:t:i:e:scnfFCaSzGb"; const static struct option longopts[] = { { "config", required_argument, NULL, 256 }, @@ -3981,30 +3814,33 @@ get_cfg(int argc, char *const *argv) { { "sw-opti", no_argument, NULL, 274 }, { "vsync-aggressive", no_argument, NULL, 275 }, { "use-ewmh-active-win", no_argument, NULL, 276 }, - { "respect-attr-shadow", no_argument, NULL, 277 }, + { "respect-prop-shadow", no_argument, NULL, 277 }, { "unredir-if-possible", no_argument, NULL, 278 }, // Must terminate with a NULL entry { NULL, 0, NULL, 0 }, }; struct options_tmp cfgtmp = { - .no_dock_shadow = False, - .no_dnd_shadow = False, + .no_dock_shadow = false, + .no_dnd_shadow = false, .menu_opacity = 1.0, }; - Bool shadow_enable = False, fading_enable = False; + bool shadow_enable = false, fading_enable = false; int o, longopt_idx, i; char *config_file = NULL; char *lc_numeric_old = mstrcpy(setlocale(LC_NUMERIC, NULL)); for (i = 0; i < NUM_WINTYPES; ++i) { - opts.wintype_fade[i] = False; - opts.wintype_shadow[i] = False; - opts.wintype_opacity[i] = 1.0; + ps->o.wintype_fade[i] = false; + ps->o.wintype_shadow[i] = false; + ps->o.wintype_opacity[i] = 1.0; } // Pre-parse the commandline arguments to check for --config and invalid // switches + // Must reset optind to 0 here in case we reread the commandline + // arguments + optind = 1; while (-1 != (o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) { if (256 == o) @@ -4014,7 +3850,7 @@ get_cfg(int argc, char *const *argv) { } #ifdef CONFIG_LIBCONFIG - parse_config(config_file, &cfgtmp); + parse_config(ps, config_file, &cfgtmp); #endif // Parse commandline arguments. Range checking will be done later. @@ -4029,56 +3865,56 @@ get_cfg(int argc, char *const *argv) { switch (o) { // Short options case 'd': - opts.display = optarg; + ps->o.display = mstrcpy(optarg); break; case 'D': - opts.fade_delta = atoi(optarg); + ps->o.fade_delta = atoi(optarg); break; case 'I': - opts.fade_in_step = normalize_d(atof(optarg)) * OPAQUE; + ps->o.fade_in_step = normalize_d(atof(optarg)) * OPAQUE; break; case 'O': - opts.fade_out_step = normalize_d(atof(optarg)) * OPAQUE; + ps->o.fade_out_step = normalize_d(atof(optarg)) * OPAQUE; break; case 'c': - shadow_enable = True; + shadow_enable = true; break; case 'C': - cfgtmp.no_dock_shadow = True; + cfgtmp.no_dock_shadow = true; break; case 'G': - cfgtmp.no_dnd_shadow = True; + cfgtmp.no_dnd_shadow = true; break; case 'm': cfgtmp.menu_opacity = atof(optarg); break; case 'f': case 'F': - fading_enable = True; + fading_enable = true; break; case 'S': - opts.synchronize = True; + ps->o.synchronize = true; break; case 'r': - opts.shadow_radius = atoi(optarg); + ps->o.shadow_radius = atoi(optarg); break; case 'o': - opts.shadow_opacity = atof(optarg); + ps->o.shadow_opacity = atof(optarg); break; case 'l': - opts.shadow_offset_x = atoi(optarg); + ps->o.shadow_offset_x = atoi(optarg); break; case 't': - opts.shadow_offset_y = atoi(optarg); + ps->o.shadow_offset_y = atoi(optarg); break; case 'i': - opts.inactive_opacity = (normalize_d(atof(optarg)) * OPAQUE); + ps->o.inactive_opacity = (normalize_d(atof(optarg)) * OPAQUE); break; case 'e': - opts.frame_opacity = atof(optarg); + ps->o.frame_opacity = atof(optarg); break; case 'z': - opts.clear_shadow = True; + ps->o.clear_shadow = true; break; case 'n': case 'a': @@ -4087,7 +3923,7 @@ get_cfg(int argc, char *const *argv) { "-n, -a, and -s have been removed.\n"); break; case 'b': - opts.fork_after_register = True; + ps->o.fork_after_register = true; break; // Long options case 256: @@ -4095,95 +3931,94 @@ get_cfg(int argc, char *const *argv) { break; case 257: // --shadow-red - opts.shadow_red = atof(optarg); + ps->o.shadow_red = atof(optarg); break; case 258: // --shadow-green - opts.shadow_green = atof(optarg); + ps->o.shadow_green = atof(optarg); break; case 259: // --shadow-blue - opts.shadow_blue = atof(optarg); + ps->o.shadow_blue = atof(optarg); break; case 260: // --inactive-opacity-override - opts.inactive_opacity_override = True; + ps->o.inactive_opacity_override = true; break; case 261: // --inactive-dim - opts.inactive_dim = atof(optarg); + ps->o.inactive_dim = atof(optarg); break; case 262: // --mark-wmwin-focused - opts.mark_wmwin_focused = True; + ps->o.mark_wmwin_focused = true; break; case 263: // --shadow-exclude - condlst_add(&opts.shadow_blacklist, optarg); + condlst_add(&ps->o.shadow_blacklist, optarg); break; case 264: // --mark-ovredir-focused - opts.mark_ovredir_focused = True; + ps->o.mark_ovredir_focused = true; break; case 265: // --no-fading-openclose - opts.no_fading_openclose = True; + ps->o.no_fading_openclose = true; break; case 266: // --shadow-ignore-shaped - opts.shadow_ignore_shaped = True; + ps->o.shadow_ignore_shaped = true; break; case 267: // --detect-rounded-corners - opts.detect_rounded_corners = True; + ps->o.detect_rounded_corners = true; break; case 268: // --detect-client-opacity - opts.detect_client_opacity = True; + ps->o.detect_client_opacity = true; break; case 269: // --refresh-rate - opts.refresh_rate = atoi(optarg); + ps->o.refresh_rate = atoi(optarg); break; case 270: // --vsync - parse_vsync(optarg); + parse_vsync(ps, optarg); break; case 271: // --alpha-step - opts.alpha_step = atof(optarg); + ps->o.alpha_step = atof(optarg); break; case 272: // --dbe - opts.dbe = True; + ps->o.dbe = true; break; case 273: // --paint-on-overlay - opts.paint_on_overlay = True; + ps->o.paint_on_overlay = true; break; case 274: // --sw-opti - opts.sw_opti = True; + ps->o.sw_opti = true; break; case 275: // --vsync-aggressive - opts.vsync_aggressive = True; + ps->o.vsync_aggressive = true; break; case 276: // --use-ewmh-active-win - opts.use_ewmh_active_win = True; + ps->o.use_ewmh_active_win = true; break; case 277: - // --respect-attr-shadow - opts.respect_attr_shadow = True; + // --respect-prop-shadow + ps->o.respect_prop_shadow = true; break; case 278: // --unredir-if-possible - opts.unredir_if_possible = True; + ps->o.unredir_if_possible = true; break; default: usage(); - break; } } @@ -4192,88 +4027,91 @@ get_cfg(int argc, char *const *argv) { free(lc_numeric_old); // Range checking and option assignments - opts.fade_delta = max_i(opts.fade_delta, 1); - opts.shadow_radius = max_i(opts.shadow_radius, 1); - opts.shadow_red = normalize_d(opts.shadow_red); - opts.shadow_green = normalize_d(opts.shadow_green); - opts.shadow_blue = normalize_d(opts.shadow_blue); - opts.inactive_dim = normalize_d(opts.inactive_dim); - opts.frame_opacity = normalize_d(opts.frame_opacity); - opts.shadow_opacity = normalize_d(opts.shadow_opacity); + ps->o.fade_delta = max_i(ps->o.fade_delta, 1); + ps->o.shadow_radius = max_i(ps->o.shadow_radius, 1); + ps->o.shadow_red = normalize_d(ps->o.shadow_red); + ps->o.shadow_green = normalize_d(ps->o.shadow_green); + ps->o.shadow_blue = normalize_d(ps->o.shadow_blue); + ps->o.inactive_dim = normalize_d(ps->o.inactive_dim); + ps->o.frame_opacity = normalize_d(ps->o.frame_opacity); + ps->o.shadow_opacity = normalize_d(ps->o.shadow_opacity); cfgtmp.menu_opacity = normalize_d(cfgtmp.menu_opacity); - opts.refresh_rate = normalize_i_range(opts.refresh_rate, 0, 300); - opts.alpha_step = normalize_d_range(opts.alpha_step, 0.01, 1.0); - if (OPAQUE == opts.inactive_opacity) { - opts.inactive_opacity = 0; + ps->o.refresh_rate = normalize_i_range(ps->o.refresh_rate, 0, 300); + ps->o.alpha_step = normalize_d_range(ps->o.alpha_step, 0.01, 1.0); + if (OPAQUE == ps->o.inactive_opacity) { + ps->o.inactive_opacity = 0; } if (shadow_enable) - wintype_arr_enable(opts.wintype_shadow); - opts.wintype_shadow[WINTYPE_DESKTOP] = False; + wintype_arr_enable(ps->o.wintype_shadow); + ps->o.wintype_shadow[WINTYPE_DESKTOP] = false; if (cfgtmp.no_dock_shadow) - opts.wintype_shadow[WINTYPE_DOCK] = False; + ps->o.wintype_shadow[WINTYPE_DOCK] = false; if (cfgtmp.no_dnd_shadow) - opts.wintype_shadow[WINTYPE_DND] = False; + ps->o.wintype_shadow[WINTYPE_DND] = false; if (fading_enable) - wintype_arr_enable(opts.wintype_fade); + wintype_arr_enable(ps->o.wintype_fade); if (1.0 != cfgtmp.menu_opacity) { - opts.wintype_opacity[WINTYPE_DROPDOWN_MENU] = cfgtmp.menu_opacity; - opts.wintype_opacity[WINTYPE_POPUP_MENU] = cfgtmp.menu_opacity; + ps->o.wintype_opacity[WINTYPE_DROPDOWN_MENU] = cfgtmp.menu_opacity; + ps->o.wintype_opacity[WINTYPE_POPUP_MENU] = cfgtmp.menu_opacity; } // Other variables determined by options // Determine whether we need to track focus changes - if (opts.inactive_opacity || opts.inactive_dim) { - opts.track_focus = True; + if (ps->o.inactive_opacity || ps->o.inactive_dim) { + ps->o.track_focus = true; } // Determine whether we need to track window name and class - if (opts.shadow_blacklist || opts.fade_blacklist) - opts.track_wdata = True; + if (ps->o.shadow_blacklist || ps->o.fade_blacklist) + ps->o.track_wdata = true; } +/** + * Fetch all required atoms and save them to a session. + */ static void -get_atoms(void) { - opacity_atom = XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False); - frame_extents_atom = XInternAtom(dpy, "_NET_FRAME_EXTENTS", False); - client_atom = XInternAtom(dpy, "WM_STATE", False); - name_atom = XA_WM_NAME; - name_ewmh_atom = XInternAtom(dpy, "_NET_WM_NAME", False); - class_atom = XA_WM_CLASS; - transient_atom = XA_WM_TRANSIENT_FOR; - ewmh_active_win_atom = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); - compton_shadow_atom = XInternAtom(dpy, "_COMPTON_SHADOW", False); +init_atoms(session_t *ps) { + ps->atom_opacity = XInternAtom(ps->dpy, "_NET_WM_WINDOW_OPACITY", False); + ps->atom_frame_extents = XInternAtom(ps->dpy, "_NET_FRAME_EXTENTS", False); + ps->atom_client = XInternAtom(ps->dpy, "WM_STATE", False); + ps->atom_name = XA_WM_NAME; + ps->atom_name_ewmh = XInternAtom(ps->dpy, "_NET_WM_NAME", False); + ps->atom_class = XA_WM_CLASS; + ps->atom_transient = XA_WM_TRANSIENT_FOR; + ps->atom_ewmh_active_win = XInternAtom(ps->dpy, "_NET_ACTIVE_WINDOW", False); + ps->atom_compton_shadow = XInternAtom(ps->dpy, "_COMPTON_SHADOW", False); - win_type_atom = XInternAtom(dpy, + ps->atom_win_type = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE", False); - win_type[WINTYPE_UNKNOWN] = 0; - win_type[WINTYPE_DESKTOP] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_UNKNOWN] = 0; + ps->atoms_wintypes[WINTYPE_DESKTOP] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False); - win_type[WINTYPE_DOCK] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_DOCK] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); - win_type[WINTYPE_TOOLBAR] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_TOOLBAR] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False); - win_type[WINTYPE_MENU] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_MENU] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_MENU", False); - win_type[WINTYPE_UTILITY] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_UTILITY] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False); - win_type[WINTYPE_SPLASH] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_SPLASH] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False); - win_type[WINTYPE_DIALOG] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_DIALOG] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); - win_type[WINTYPE_NORMAL] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_NORMAL] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False); - win_type[WINTYPE_DROPDOWN_MENU] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_DROPDOWN_MENU] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False); - win_type[WINTYPE_POPUP_MENU] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_POPUP_MENU] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_POPUP_MENU", False); - win_type[WINTYPE_TOOLTIP] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_TOOLTIP] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_TOOLTIP", False); - win_type[WINTYPE_NOTIFY] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_NOTIFY] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_NOTIFICATION", False); - win_type[WINTYPE_COMBO] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_COMBO] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_COMBO", False); - win_type[WINTYPE_DND] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_DND] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_DND", False); } @@ -4281,49 +4119,49 @@ get_atoms(void) { * Update refresh rate info with X Randr extension. */ static void -update_refresh_rate(Display *dpy) { +update_refresh_rate(session_t *ps) { XRRScreenConfiguration* randr_info; - if (!(randr_info = XRRGetScreenInfo(dpy, root))) + if (!(randr_info = XRRGetScreenInfo(ps->dpy, ps->root))) return; - refresh_rate = XRRConfigCurrentRate(randr_info); + ps->refresh_rate = XRRConfigCurrentRate(randr_info); XRRFreeScreenConfigInfo(randr_info); - if (refresh_rate) - refresh_intv = NS_PER_SEC / refresh_rate; + if (ps->refresh_rate) + ps->refresh_intv = NS_PER_SEC / ps->refresh_rate; else - refresh_intv = 0; + ps->refresh_intv = 0; } /** * Initialize refresh-rated based software optimization. * - * @return True for success, False otherwise + * @return true for success, false otherwise */ -static Bool -sw_opti_init(void) { +static bool +sw_opti_init(session_t *ps) { // Prepare refresh rate // Check if user provides one - refresh_rate = opts.refresh_rate; - if (refresh_rate) - refresh_intv = NS_PER_SEC / refresh_rate; + ps->refresh_rate = ps->o.refresh_rate; + if (ps->refresh_rate) + ps->refresh_intv = NS_PER_SEC / ps->refresh_rate; // Auto-detect refresh rate otherwise - if (!refresh_rate && randr_exists) { - update_refresh_rate(dpy); + if (!ps->refresh_rate && ps->randr_exists) { + update_refresh_rate(ps); } // Turn off vsync_sw if we can't get the refresh rate - if (!refresh_rate) - return False; + if (!ps->refresh_rate) + return false; // Monitor screen changes only if vsync_sw is enabled and we are using // an auto-detected refresh rate - if (randr_exists && !opts.refresh_rate) - XRRSelectInput(dpy, root, RRScreenChangeNotify); + if (ps->randr_exists && !ps->o.refresh_rate) + XRRSelectInput(ps->dpy, ps->root, RRScreenChangeNotify); - return True; + return true; } /** @@ -4353,18 +4191,23 @@ lceil_ntimes(long dividend, long divisor) { * problems */ static int -evpoll(struct pollfd *fd, int timeout) { +evpoll(session_t *ps, int timeout) { + struct pollfd ufd = { + .fd = ConnectionNumber(ps->dpy), + .events = POLLIN + }; + // Always wait infinitely if asked so, to minimize CPU usage if (timeout < 0) { - int ret = poll(fd, 1, timeout); - // Reset fade_time so the fading steps during idling are not counted - fade_time = get_time_ms(); + int ret = poll(&ufd, 1, timeout); + // Reset ps->fade_time so the fading steps during idling are not counted + ps->fade_time = get_time_ms(); return ret; } // Just do a poll() if we are not using optimization - if (!opts.sw_opti) - return poll(fd, 1, timeout); + if (!ps->o.sw_opti) + return poll(&ufd, 1, timeout); // Convert the old timeout to struct timespec struct timespec next_paint_tmout = { @@ -4374,7 +4217,7 @@ evpoll(struct pollfd *fd, int timeout) { // Get the nanosecond offset of the time when the we reach the timeout // I don't think a 32-bit long could overflow here. - long target_relative_offset = (next_paint_tmout.tv_nsec + get_time_timespec().tv_nsec - paint_tm_offset) % NS_PER_SEC; + long target_relative_offset = (next_paint_tmout.tv_nsec + get_time_timespec().tv_nsec - ps->paint_tm_offset) % NS_PER_SEC; if (target_relative_offset < 0) target_relative_offset += NS_PER_SEC; @@ -4383,39 +4226,39 @@ evpoll(struct pollfd *fd, int timeout) { // If the target time is sufficiently close to a refresh time, don't add // an offset, to avoid certain blocking conditions. if ((target_relative_offset % NS_PER_SEC) < SW_OPTI_TOLERANCE) - return poll(fd, 1, timeout); + return poll(&ufd, 1, timeout); // Add an offset so we wait until the next refresh after timeout - next_paint_tmout.tv_nsec += lceil_ntimes(target_relative_offset, refresh_intv) - target_relative_offset; + next_paint_tmout.tv_nsec += lceil_ntimes(target_relative_offset, ps->refresh_intv) - target_relative_offset; if (next_paint_tmout.tv_nsec > NS_PER_SEC) { next_paint_tmout.tv_nsec -= NS_PER_SEC; ++next_paint_tmout.tv_sec; } - return ppoll(fd, 1, &next_paint_tmout, NULL); + return ppoll(&ufd, 1, &next_paint_tmout, NULL); } /** * Initialize DRM VSync. * - * @return True for success, False otherwise + * @return true for success, false otherwise */ -static Bool -vsync_drm_init(void) { +static bool +vsync_drm_init(session_t *ps) { #ifdef CONFIG_VSYNC_DRM // Should we always open card0? - if ((drm_fd = open("/dev/dri/card0", O_RDWR)) < 0) { + if ((ps->drm_fd = open("/dev/dri/card0", O_RDWR)) < 0) { fprintf(stderr, "vsync_drm_init(): Failed to open device.\n"); - return False; + return false; } - if (vsync_drm_wait()) - return False; + if (vsync_drm_wait(ps)) + return false; - return True; + return true; #else fprintf(stderr, "Program not compiled with DRM VSync support.\n"); - return False; + return false; #endif } @@ -4426,7 +4269,7 @@ vsync_drm_init(void) { * Stolen from: https://github.com/MythTV/mythtv/blob/master/mythtv/libs/libmythtv/vsync.cpp */ static int -vsync_drm_wait(void) { +vsync_drm_wait(session_t *ps) { int ret = -1; drm_wait_vblank_t vbl; @@ -4434,7 +4277,7 @@ vsync_drm_wait(void) { vbl.request.sequence = 1; do { - ret = ioctl(drm_fd, DRM_IOCTL_WAIT_VBLANK, &vbl); + ret = ioctl(ps->drm_fd, DRM_IOCTL_WAIT_VBLANK, &vbl); vbl.request.type &= ~_DRM_VBLANK_RELATIVE; } while (ret && errno == EINTR); @@ -4443,7 +4286,7 @@ vsync_drm_wait(void) { "unimplemented in this drmver?\n"); return ret; - + } #endif @@ -4453,26 +4296,26 @@ vsync_drm_wait(void) { * Stolen from: http://git.tuxfamily.org/?p=ccm/cairocompmgr.git;a=commitdiff;h=efa4ceb97da501e8630ca7f12c99b1dce853c73e * Possible original source: http://www.inb.uni-luebeck.de/~boehme/xvideo_sync.html * - * @return True for success, False otherwise + * @return true for success, false otherwise */ -static Bool -vsync_opengl_init(void) { +static bool +vsync_opengl_init(session_t *ps) { #ifdef CONFIG_VSYNC_OPENGL // Get video sync functions - glx_get_video_sync = (f_GetVideoSync) + ps->glx_get_video_sync = (f_GetVideoSync) glXGetProcAddress ((const GLubyte *) "glXGetVideoSyncSGI"); - glx_wait_video_sync = (f_WaitVideoSync) + ps->glx_wait_video_sync = (f_WaitVideoSync) glXGetProcAddress ((const GLubyte *) "glXWaitVideoSyncSGI"); - if (!glx_wait_video_sync || !glx_get_video_sync) { + if (!ps->glx_wait_video_sync || !ps->glx_get_video_sync) { fprintf(stderr, "vsync_opengl_init(): " "Failed to get glXWait/GetVideoSyncSGI function.\n"); - return False; + return false; } - - return True; + + return true; #else fprintf(stderr, "Program not compiled with OpenGL VSync support.\n"); - return False; + return false; #endif } @@ -4481,11 +4324,11 @@ vsync_opengl_init(void) { * Wait for next VSync, OpenGL method. */ static void -vsync_opengl_wait(void) { +vsync_opengl_wait(session_t *ps) { unsigned vblank_count; - glx_get_video_sync(&vblank_count); - glx_wait_video_sync(2, (vblank_count + 1) % 2, &vblank_count); + ps->glx_get_video_sync(&vblank_count); + ps->glx_wait_video_sync(2, (vblank_count + 1) % 2, &vblank_count); // I see some code calling glXSwapIntervalSGI(1) afterwards, is it required? } #endif @@ -4494,20 +4337,20 @@ vsync_opengl_wait(void) { * Wait for next VSync. */ static void -vsync_wait(void) { - if (VSYNC_NONE == opts.vsync) +vsync_wait(session_t *ps) { + if (VSYNC_NONE == ps->o.vsync) return; #ifdef CONFIG_VSYNC_DRM - if (VSYNC_DRM == opts.vsync) { - vsync_drm_wait(); + if (VSYNC_DRM == ps->o.vsync) { + vsync_drm_wait(ps); return; } #endif #ifdef CONFIG_VSYNC_OPENGL - if (VSYNC_OPENGL == opts.vsync) { - vsync_opengl_wait(); + if (VSYNC_OPENGL == ps->o.vsync) { + vsync_opengl_wait(ps); return; } #endif @@ -4522,18 +4365,18 @@ vsync_wait(void) { * Pregenerate alpha pictures. */ static void -init_alpha_picts(Display *dpy) { +init_alpha_picts(session_t *ps) { int i; - int num = lround(1.0 / opts.alpha_step) + 1; + int num = lround(1.0 / ps->o.alpha_step) + 1; - alpha_picts = malloc(sizeof(Picture) * num); + ps->alpha_picts = malloc(sizeof(Picture) * num); for (i = 0; i < num; ++i) { - double o = i * opts.alpha_step; - if ((1.0 - o) > opts.alpha_step) - alpha_picts[i] = solid_picture(dpy, False, o, 0, 0, 0); + double o = i * ps->o.alpha_step; + if ((1.0 - o) > ps->o.alpha_step) + ps->alpha_picts[i] = solid_picture(ps, false, o, 0, 0, 0); else - alpha_picts[i] = None; + ps->alpha_picts[i] = None; } } @@ -4541,12 +4384,12 @@ init_alpha_picts(Display *dpy) { * Initialize double buffer. */ static void -init_dbe(void) { - if (!(root_dbe = XdbeAllocateBackBufferName(dpy, - (opts.paint_on_overlay ? overlay: root), XdbeCopied))) { +init_dbe(session_t *ps) { + if (!(ps->root_dbe = XdbeAllocateBackBufferName(ps->dpy, + (ps->o.paint_on_overlay ? ps->overlay: ps->root), XdbeCopied))) { fprintf(stderr, "Failed to create double buffer. Double buffering " "turned off.\n"); - opts.dbe = False; + ps->o.dbe = false; return; } } @@ -4555,27 +4398,27 @@ init_dbe(void) { * Initialize X composite overlay window. */ static void -init_overlay(void) { - overlay = XCompositeGetOverlayWindow(dpy, root); - if (overlay) { +init_overlay(session_t *ps) { + ps->overlay = XCompositeGetOverlayWindow(ps->dpy, ps->root); + if (ps->overlay) { // Set window region of the overlay window, code stolen from // compiz-0.8.8 - XserverRegion region = XFixesCreateRegion (dpy, NULL, 0); - XFixesSetWindowShapeRegion(dpy, overlay, ShapeBounding, 0, 0, 0); - XFixesSetWindowShapeRegion(dpy, overlay, ShapeInput, 0, 0, region); - XFixesDestroyRegion (dpy, region); + XserverRegion region = XFixesCreateRegion(ps->dpy, NULL, 0); + XFixesSetWindowShapeRegion(ps->dpy, ps->overlay, ShapeBounding, 0, 0, 0); + XFixesSetWindowShapeRegion(ps->dpy, ps->overlay, ShapeInput, 0, 0, region); + XFixesDestroyRegion(ps->dpy, region); // Listen to Expose events on the overlay - XSelectInput(dpy, overlay, ExposureMask); + XSelectInput(ps->dpy, ps->overlay, ExposureMask); // Retrieve DamageNotify on root window if we are painting on an // overlay - // root_damage = XDamageCreate(dpy, root, XDamageReportNonEmpty); + // root_damage = XDamageCreate(ps->dpy, root, XDamageReportNonEmpty); } else { fprintf(stderr, "Cannot get X Composite overlay window. Falling " "back to painting on root window.\n"); - opts.paint_on_overlay = False; + ps->o.paint_on_overlay = false; } } @@ -4583,23 +4426,23 @@ init_overlay(void) { * Redirect all windows. */ static void -redir_start(Display *dpy) { - if (!redirected) { +redir_start(session_t *ps) { + if (!ps->redirected) { #ifdef DEBUG_REDIR printf("redir_start(): Screen redirected.\n"); #endif // Map overlay window. Done firstly according to this: // https://bugzilla.gnome.org/show_bug.cgi?id=597014 - if (overlay) - XMapWindow(dpy, overlay); + if (ps->overlay) + XMapWindow(ps->dpy, ps->overlay); - XCompositeRedirectSubwindows(dpy, root, CompositeRedirectManual); + XCompositeRedirectSubwindows(ps->dpy, ps->root, CompositeRedirectManual); // Must call XSync() here - XSync(dpy, False); + XSync(ps->dpy, False); - redirected = True; + ps->redirected = true; } } @@ -4607,103 +4450,252 @@ redir_start(Display *dpy) { * Unredirect all windows. */ static void -redir_stop(Display *dpy) { - if (redirected) { +redir_stop(session_t *ps) { + if (ps->redirected) { #ifdef DEBUG_REDIR printf("redir_stop(): Screen unredirected.\n"); #endif // Destroy all Pictures as they expire once windows are unredirected // If we don't destroy them here, looks like the resources are just // kept inaccessible somehow - for (win *w = list; w; w = w->next) { - free_pixmap(dpy, &w->pixmap); - free_picture(dpy, &w->picture); + for (win *w = ps->list; w; w = w->next) { + free_pixmap(ps, &w->pixmap); + free_picture(ps, &w->picture); } - XCompositeUnredirectSubwindows(dpy, root, CompositeRedirectManual); - + XCompositeUnredirectSubwindows(ps->dpy, ps->root, CompositeRedirectManual); // Unmap overlay window - if (overlay) - XUnmapWindow(dpy, overlay); + if (ps->overlay) + XUnmapWindow(ps->dpy, ps->overlay); // Must call XSync() here - XSync(dpy, False); - - redirected = False; + XSync(ps->dpy, False); + ps->redirected = false; } } -int -main(int argc, char **argv) { - XEvent ev; - Window root_return, parent_return; - Window *children; - unsigned int nchildren; +/** + * Initialize a session. + * + * @param ps_old old session, from which the function will take the X + * connection, then free it + * @param argc number of commandline arguments + * @param argv commandline arguments + */ +static session_t * +session_init(session_t *ps_old, int argc, char **argv) { + const static session_t s_def = { + .dpy = NULL, + .scr = 0, + .vis = NULL, + .depth = 0, + .root = None, + .root_height = 0, + .root_width = 0, + // .root_damage = None, + .overlay = None, + .root_tile = None, + .screen_reg = None, + .tgt_picture = None, + .tgt_buffer = None, + .root_dbe = None, + .reg_win = None, + .o = { + .display = NULL, + .mark_wmwin_focused = false, + .mark_ovredir_focused = false, + .fork_after_register = false, + .synchronize = false, + .detect_rounded_corners = false, + .paint_on_overlay = false, + .unredir_if_possible = false, + + .refresh_rate = 0, + .sw_opti = false, + .vsync = VSYNC_NONE, + .dbe = false, + .vsync_aggressive = false, + + .wintype_shadow = { false }, + .shadow_red = 0.0, + .shadow_green = 0.0, + .shadow_blue = 0.0, + .shadow_radius = 12, + .shadow_offset_x = -15, + .shadow_offset_y = -15, + .shadow_opacity = .75, + .clear_shadow = false, + .shadow_blacklist = NULL, + .shadow_ignore_shaped = false, + .respect_prop_shadow = false, + + .wintype_fade = { false }, + .fade_in_step = 0.028 * OPAQUE, + .fade_out_step = 0.03 * OPAQUE, + .fade_delta = 10, + .no_fading_openclose = false, + .fade_blacklist = NULL, + + .wintype_opacity = { 0.0 }, + .inactive_opacity = 0, + .inactive_opacity_override = false, + .frame_opacity = 0.0, + .detect_client_opacity = false, + .inactive_dim = 0.0, + .alpha_step = 0.03, + .use_ewmh_active_win = false, + + .track_focus = false, + .track_wdata = false, + }, + + .all_damage = None, + .time_start = { 0, 0 }, + .redirected = false, + .unredir_possible = false, + .alpha_picts = NULL, + .reg_ignore_expire = false, + .idling = false, + .fade_time = 0, + .ignore_head = NULL, + .ignore_tail = NULL, + .reset = false, + + .expose_rects = NULL, + .size_expose = 0, + .n_expose = 0, + + .list = NULL, + .active_win = NULL, + .black_picture = None, + .dim_picture = None, + .cshadow_picture = None, + .gaussian_map = NULL, + .cgsize = 0, + .shadow_corner = NULL, + .shadow_top = NULL, + + .refresh_rate = 0, + .refresh_intv = 0UL, + .paint_tm_offset = 0L, + + .drm_fd = 0, + + .glx_context = None, + .glx_get_video_sync = NULL, + .glx_wait_video_sync = NULL, + + .xfixes_event = 0, + .xfixes_error = 0, + .damage_event = 0, + .damage_error = 0, + .render_event = 0, + .render_error = 0, + .composite_event = 0, + .composite_error = 0, + .composite_opcode = 0, + .has_name_pixmap = false, + .shape_exists = false, + .shape_event = 0, + .shape_error = 0, + .randr_exists = 0, + .randr_event = 0, + .randr_error = 0, + .glx_exists = false, + .glx_event = 0, + .glx_error = 0, + .dbe_exists = false, + + .atom_opacity = None, + .atom_frame_extents = None, + .atom_client = None, + .atom_name = None, + .atom_name_ewmh = None, + .atom_class = None, + .atom_transient = None, + .atom_ewmh_active_win = None, + .atom_compton_shadow = None, + .atom_win_type = None, + .atoms_wintypes = { 0 } + }; + int i; - XRenderPictureAttributes pa; - struct pollfd ufd; - int composite_major, composite_minor; - win *t; - gettimeofday(&time_start, NULL); + // Allocate a session and copy default values into it + session_t *ps = malloc(sizeof(session_t)); + memcpy(ps, &s_def, sizeof(session_t)); + ps_g = ps; + ps->ignore_tail = &ps->ignore_head; + gettimeofday(&ps->time_start, NULL); - // Set locale so window names with special characters are interpreted - // correctly - setlocale (LC_ALL, ""); + get_cfg(ps, argc, argv); - get_cfg(argc, argv); + // Inherit old Display if possible, primarily for resource leak checking + if (ps_old && ps_old->dpy) + ps->dpy = ps_old->dpy; - dpy = XOpenDisplay(opts.display); - if (!dpy) { - fprintf(stderr, "Can't open display\n"); - exit(1); + // Open Display + if (!ps->dpy) { + ps->dpy = XOpenDisplay(ps->o.display); + if (!ps->dpy) { + fprintf(stderr, "Can't open display\n"); + exit(1); + } } XSetErrorHandler(error); - if (opts.synchronize) { - XSynchronize(dpy, 1); + if (ps->o.synchronize) { + XSynchronize(ps->dpy, 1); } - scr = DefaultScreen(dpy); - root = RootWindow(dpy, scr); + ps->scr = DefaultScreen(ps->dpy); + ps->root = RootWindow(ps->dpy, ps->scr); - if (!XRenderQueryExtension(dpy, &render_event, &render_error)) { + ps->vis = DefaultVisual(ps->dpy, ps->scr); + ps->depth = DefaultDepth(ps->dpy, ps->scr); + + if (!XRenderQueryExtension(ps->dpy, + &ps->render_event, &ps->render_error)) { fprintf(stderr, "No render extension\n"); exit(1); } - if (!XQueryExtension(dpy, COMPOSITE_NAME, &composite_opcode, - &composite_event, &composite_error)) { + if (!XQueryExtension(ps->dpy, COMPOSITE_NAME, &ps->composite_opcode, + &ps->composite_event, &ps->composite_error)) { fprintf(stderr, "No composite extension\n"); exit(1); } - XCompositeQueryVersion(dpy, &composite_major, &composite_minor); + { + int composite_major = 0, composite_minor = 0; - if (composite_major > 0 || composite_minor >= 2) { - has_name_pixmap = True; + XCompositeQueryVersion(ps->dpy, &composite_major, &composite_minor); + + if (composite_major > 0 || composite_minor >= 2) { + ps->has_name_pixmap = true; + } } - if (!XDamageQueryExtension(dpy, &damage_event, &damage_error)) { + if (!XDamageQueryExtension(ps->dpy, &ps->damage_event, &ps->damage_error)) { fprintf(stderr, "No damage extension\n"); exit(1); } - if (!XFixesQueryExtension(dpy, &xfixes_event, &xfixes_error)) { + if (!XFixesQueryExtension(ps->dpy, &ps->xfixes_event, &ps->xfixes_error)) { fprintf(stderr, "No XFixes extension\n"); exit(1); } // Query X Shape - if (XShapeQueryExtension(dpy, &shape_event, &shape_error)) { - shape_exists = True; + if (XShapeQueryExtension(ps->dpy, &ps->shape_event, &ps->shape_error)) { + ps->shape_exists = true; } // Query X RandR - if (opts.sw_opti && !opts.refresh_rate) { - if (XRRQueryExtension(dpy, &randr_event, &randr_error)) - randr_exists = True; + if (ps->o.sw_opti && !ps->o.refresh_rate) { + if (XRRQueryExtension(ps->dpy, &ps->randr_event, &ps->randr_error)) + ps->randr_exists = true; else fprintf(stderr, "No XRandR extension, automatic refresh rate " "detection impossible.\n"); @@ -4711,170 +4703,368 @@ main(int argc, char **argv) { #ifdef CONFIG_VSYNC_OPENGL // Query X GLX extension - if (VSYNC_OPENGL == opts.vsync) { - if (glXQueryExtension(dpy, &glx_event, &glx_error)) - glx_exists = True; + if (VSYNC_OPENGL == ps->o.vsync) { + if (glXQueryExtension(ps->dpy, &ps->glx_event, &ps->glx_error)) + ps->glx_exists = true; else { fprintf(stderr, "No GLX extension, OpenGL VSync impossible.\n"); - opts.vsync = VSYNC_NONE; + ps->o.vsync = VSYNC_NONE; } } #endif // Query X DBE extension - if (opts.dbe) { + if (ps->o.dbe) { int dbe_ver_major = 0, dbe_ver_minor = 0; - if (XdbeQueryExtension(dpy, &dbe_ver_major, &dbe_ver_minor)) + if (XdbeQueryExtension(ps->dpy, &dbe_ver_major, &dbe_ver_minor)) if (dbe_ver_major >= 1) - dbe_exists = True; + ps->dbe_exists = true; else fprintf(stderr, "DBE extension version too low. Double buffering " "impossible.\n"); else { fprintf(stderr, "No DBE extension. Double buffering impossible.\n"); } - if (!dbe_exists) - opts.dbe = False; + if (!ps->dbe_exists) + ps->o.dbe = false; } - register_cm((VSYNC_OPENGL == opts.vsync)); + register_cm(ps, (VSYNC_OPENGL == ps->o.vsync)); // Initialize software optimization - if (opts.sw_opti) - opts.sw_opti = sw_opti_init(); + if (ps->o.sw_opti) + ps->o.sw_opti = sw_opti_init(ps); // Initialize DRM/OpenGL VSync - if ((VSYNC_DRM == opts.vsync && !vsync_drm_init()) - || (VSYNC_OPENGL == opts.vsync && !vsync_opengl_init())) - opts.vsync = VSYNC_NONE; + if ((VSYNC_DRM == ps->o.vsync && !vsync_drm_init(ps)) + || (VSYNC_OPENGL == ps->o.vsync && !vsync_opengl_init(ps))) + ps->o.vsync = VSYNC_NONE; // Overlay must be initialized before double buffer - if (opts.paint_on_overlay) - init_overlay(); + if (ps->o.paint_on_overlay) + init_overlay(ps); - if (opts.dbe) - init_dbe(); + if (ps->o.dbe) + init_dbe(ps); - if (opts.fork_after_register) fork_after(); + if (ps->o.fork_after_register) fork_after(); - get_atoms(); - init_alpha_picts(dpy); + init_atoms(ps); + init_alpha_picts(ps); - pa.subwindow_mode = IncludeInferiors; + ps->gaussian_map = make_gaussian_map(ps->o.shadow_radius); + presum_gaussian(ps, ps->gaussian_map); - gaussian_map = make_gaussian_map(dpy, opts.shadow_radius); - presum_gaussian(gaussian_map); + ps->root_width = DisplayWidth(ps->dpy, ps->scr); + ps->root_height = DisplayHeight(ps->dpy, ps->scr); - root_width = DisplayWidth(dpy, scr); - root_height = DisplayHeight(dpy, scr); + rebuild_screen_reg(ps); - rebuild_screen_reg(dpy); + { + XRenderPictureAttributes pa; + pa.subwindow_mode = IncludeInferiors; - root_picture = XRenderCreatePicture(dpy, root, - XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), - CPSubwindowMode, &pa); - if (opts.paint_on_overlay) { - tgt_picture = XRenderCreatePicture(dpy, overlay, - XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), + ps->root_picture = XRenderCreatePicture(ps->dpy, ps->root, + XRenderFindVisualFormat(ps->dpy, ps->vis), CPSubwindowMode, &pa); - } - else { - tgt_picture = root_picture; + if (ps->o.paint_on_overlay) { + ps->tgt_picture = XRenderCreatePicture(ps->dpy, ps->overlay, + XRenderFindVisualFormat(ps->dpy, ps->vis), + CPSubwindowMode, &pa); + } + else { + ps->tgt_picture = ps->root_picture; + } } - black_picture = solid_picture(dpy, True, 1, 0, 0, 0); + ps->black_picture = solid_picture(ps, true, 1, 0, 0, 0); // Generates another Picture for shadows if the color is modified by // user - if (!opts.shadow_red && !opts.shadow_green && !opts.shadow_blue) { - cshadow_picture = black_picture; + if (!ps->o.shadow_red && !ps->o.shadow_green && !ps->o.shadow_blue) { + ps->cshadow_picture = ps->black_picture; } else { - cshadow_picture = solid_picture(dpy, True, 1, - opts.shadow_red, opts.shadow_green, opts.shadow_blue); + ps->cshadow_picture = solid_picture(ps, true, 1, + ps->o.shadow_red, ps->o.shadow_green, ps->o.shadow_blue); } // Generates a picture for inactive_dim - if (opts.inactive_dim) { - dim_picture = solid_picture(dpy, True, opts.inactive_dim, 0, 0, 0); + if (ps->o.inactive_dim) { + ps->dim_picture = solid_picture(ps, true, ps->o.inactive_dim, 0, 0, 0); } - all_damage = None; - XGrabServer(dpy); + ps->all_damage = None; + XGrabServer(ps->dpy); - redir_start(dpy); + redir_start(ps); - XSelectInput(dpy, root, + XSelectInput(ps->dpy, ps->root, SubstructureNotifyMask | ExposureMask | StructureNotifyMask | PropertyChangeMask); - XQueryTree(dpy, root, &root_return, - &parent_return, &children, &nchildren); + { + Window root_return, parent_return; + Window *children; + unsigned int nchildren; - for (i = 0; i < nchildren; i++) { - add_win(dpy, children[i], i ? children[i-1] : None, False); + XQueryTree(ps->dpy, ps->root, &root_return, + &parent_return, &children, &nchildren); + + for (i = 0; i < nchildren; i++) { + add_win(ps, children[i], i ? children[i-1] : None, false); + } + + XFree(children); } - XFree(children); - if (opts.track_focus) { - recheck_focus(dpy); + if (ps->o.track_focus) { + recheck_focus(ps); } - XUngrabServer(dpy); + XUngrabServer(ps->dpy); - ufd.fd = ConnectionNumber(dpy); - ufd.events = POLLIN; + // Free the old session + if (ps_old) + free(ps_old); - if (opts.sw_opti) - paint_tm_offset = get_time_timespec().tv_nsec; + return ps; +} - reg_ignore_expire = True; +/** + * Destroy a session. + * + * Does not close the X connection or free the session_t + * structure, though. + * + * @param ps session to destroy + */ +static void +session_destroy(session_t *ps) { + redir_stop(ps); - fade_time = get_time_ms(); + // Stop listening to events on root window + XSelectInput(ps->dpy, ps->root, 0); - t = paint_preprocess(dpy, list); + // Free window linked list + { + win *next = NULL; + for (win *w = ps->list; w; w = next) { + // Must be put here to avoid segfault + next = w->next; - if (redirected) - paint_all(dpy, None, t); + if (IsViewable == w->a.map_state && !w->destroyed) + win_ev_stop(ps, w); + + free_win_res(ps, w); + free(w); + } + + ps->list = NULL; + } + + // Free alpha_picts + { + const int max = lround(1.0 / ps->o.alpha_step) + 1; + for (int i = 0; i < max; ++i) + free_picture(ps, &ps->alpha_picts[i]); + free(ps->alpha_picts); + ps->alpha_picts = NULL; + } + + // Free blacklists + free_wincondlst(&ps->o.shadow_blacklist); + free_wincondlst(&ps->o.fade_blacklist); + + // Free ignore linked list + { + ignore_t *next = NULL; + for (ignore_t *ign = ps->ignore_head; ign; ign = next) { + next = ign->next; + + free(ign); + } + + // Reset head and tail + ps->ignore_head = NULL; + ps->ignore_tail = &ps->ignore_head; + } + + // Free cshadow_picture and black_picture + if (ps->cshadow_picture == ps->black_picture) + ps->cshadow_picture = None; + else + free_picture(ps, &ps->cshadow_picture); + + free_picture(ps, &ps->black_picture); + + // Free tgt_{buffer,picture} and root_picture + if (ps->tgt_buffer == ps->tgt_picture) + ps->tgt_buffer = None; + else + free_picture(ps, &ps->tgt_buffer); + + if (ps->tgt_picture == ps->root_picture) + ps->tgt_picture = None; + else + free_picture(ps, &ps->tgt_picture); + + free_picture(ps, &ps->root_picture); + + // Free other X resources + free_picture(ps, &ps->dim_picture); + free_picture(ps, &ps->root_tile); + free_region(ps, &ps->screen_reg); + free_region(ps, &ps->all_damage); + free(ps->expose_rects); + free(ps->shadow_corner); + free(ps->shadow_top); + free(ps->gaussian_map); + free(ps->o.display); + + // Free reg_win and glx_context + if (ps->reg_win) { + XDestroyWindow(ps->dpy, ps->reg_win); + ps->reg_win = None; + } + if (ps->glx_context) { + glXDestroyContext(ps->dpy, ps->glx_context); + ps->glx_context = None; + } + + // Free double buffer + if (ps->root_dbe) { + XdbeDeallocateBackBufferName(ps->dpy, ps->root_dbe); + ps->root_dbe = None; + } + + // Close file opened for DRM VSync + if (ps->drm_fd) { + close(ps->drm_fd); + ps->drm_fd = 0; + } + + // Release overlay window + if (ps->overlay) { + XCompositeReleaseOverlayWindow(ps->dpy, ps->overlay); + ps->overlay = None; + } + + // Flush all events + XSync(ps->dpy, True); + + if (ps == ps_g) + ps_g = NULL; +} + +/** + * Do the actual work. + * + * @param ps current session + */ +static void +session_run(session_t *ps) { + win *t; + + if (ps->o.sw_opti) + ps->paint_tm_offset = get_time_timespec().tv_nsec; + + ps->reg_ignore_expire = true; + + ps->fade_time = get_time_ms(); + + t = paint_preprocess(ps, ps->list); + + if (ps->redirected) + paint_all(ps, None, t); // Initialize idling - idling = False; + ps->idling = false; // Main loop - while (1) { - Bool ev_received = False; + while (!ps->reset) { + bool ev_received = false; - while (XEventsQueued(dpy, QueuedAfterReading) - || (evpoll(&ufd, - (ev_received ? 0: (idling ? -1: fade_timeout()))) > 0)) { + while (XEventsQueued(ps->dpy, QueuedAfterReading) + || (evpoll(ps, + (ev_received ? 0: (ps->idling ? -1: fade_timeout(ps)))) > 0)) { // Sometimes poll() returns 1 but no events are actually read, // causing XNextEvent() to block, I have no idea what's wrong, so we // check for the number of events here - if (XEventsQueued(dpy, QueuedAfterReading)) { - XNextEvent(dpy, &ev); - ev_handle((XEvent *) &ev); - ev_received = True; + if (XEventsQueued(ps->dpy, QueuedAfterReading)) { + XEvent ev; + + XNextEvent(ps->dpy, &ev); + ev_handle(ps, &ev); + ev_received = true; } } // idling will be turned off during paint_preprocess() if needed - idling = True; + ps->idling = true; - t = paint_preprocess(dpy, list); + t = paint_preprocess(ps, ps->list); // If the screen is unredirected, free all_damage to stop painting - if (!redirected) - free_region(dpy, &all_damage); + if (!ps->redirected) + free_region(ps, &ps->all_damage); - if (all_damage && !is_region_empty(dpy, all_damage)) { + if (ps->all_damage && !is_region_empty(ps, ps->all_damage)) { static int paint; - paint_all(dpy, all_damage, t); - reg_ignore_expire = False; + paint_all(ps, ps->all_damage, t); + ps->reg_ignore_expire = false; paint++; - XSync(dpy, False); - all_damage = None; + XSync(ps->dpy, False); + ps->all_damage = None; } } } + +/** + * Turn on the program reset flag. + * + * This will result in compton resetting itself after next paint. + */ +static void +reset_enable(int __attribute__((unused)) signum) { + session_t * const ps = ps_g; + + ps->reset = true; +} + +/** + * The function that everybody knows. + */ +int +main(int argc, char **argv) { + // Set locale so window names with special characters are interpreted + // correctly + setlocale(LC_ALL, ""); + + // Set up SIGUSR1 signal handler to reset program + { + sigset_t block_mask; + sigemptyset(&block_mask); + const struct sigaction action= { + .sa_handler = reset_enable, + .sa_mask = block_mask, + .sa_flags = 0 + }; + sigaction(SIGUSR1, &action, NULL); + } + + // Main loop + session_t *ps_old = ps_g; + while (1) { + ps_g = session_init(ps_old, argc, argv); + session_run(ps_g); + ps_old = ps_g; + session_destroy(ps_g); + } + + free(ps_g); + + return 0; +} diff --git a/src/compton.h b/src/compton.h index 2b3e0860..51f59eb9 100644 --- a/src/compton.h +++ b/src/compton.h @@ -15,6 +15,7 @@ // #define DEBUG_WINDATA 1 // #define DEBUG_WINMATCH 1 // #define DEBUG_REDIR 1 +// #define DEBUG_ALLOC_REG 1 // #define MONITOR_REPAINT 1 // Whether to enable PCRE regular expression support in blacklists, enabled @@ -48,8 +49,8 @@ #include #include #include - #include +#include #ifdef CONFIG_REGEX_PCRE #include @@ -75,6 +76,7 @@ #include #include #include +#include #ifdef CONFIG_VSYNC_DRM #include @@ -90,58 +92,6 @@ #include #endif -static void -print_timestamp(void); - -#ifdef DEBUG_ALLOC_REG - -#include -#define BACKTRACE_SIZE 5 - -/** - * Print current backtrace, excluding the first two items. - * - * Stolen from glibc manual. - */ -static inline void -print_backtrace(void) { - void *array[BACKTRACE_SIZE]; - size_t size; - char **strings; - - size = backtrace(array, BACKTRACE_SIZE); - strings = backtrace_symbols(array, size); - - for (size_t i = 2; i < size; i++) - printf ("%s\n", strings[i]); - - free(strings); -} - -static inline XserverRegion -XFixesCreateRegion_(Display *dpy, XRectangle *p, int n, - const char *func, int line) { - XserverRegion reg = XFixesCreateRegion(dpy, p, n); - print_timestamp(); - printf("%#010lx: XFixesCreateRegion() in %s():%d\n", reg, func, line); - print_backtrace(); - fflush(stdout); - return reg; -} - -static inline void -XFixesDestroyRegion_(Display *dpy, XserverRegion reg, - const char *func, int line) { - XFixesDestroyRegion(dpy, reg); - print_timestamp(); - printf("%#010lx: XFixesDestroyRegion() in %s():%d\n", reg, func, line); - fflush(stdout); -} - -#define XFixesCreateRegion(dpy, p, n) XFixesCreateRegion_(dpy, p, n, __func__, __LINE__) -#define XFixesDestroyRegion(dpy, reg) XFixesDestroyRegion_(dpy, reg, __func__, __LINE__) -#endif - // === Constants === #if !(COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2) #error libXcomposite version unsupported @@ -150,10 +100,6 @@ XFixesDestroyRegion_(Display *dpy, XserverRegion reg, #define ROUNDED_PERCENT 0.05 #define ROUNDED_PIXELS 10 -// For printing timestamps -#include -extern struct timeval time_start; - #define OPAQUE 0xffffffff #define REGISTER_PROP "_NET_WM_CM_S" @@ -194,7 +140,7 @@ typedef enum { WINTYPE_COMBO, WINTYPE_DND, NUM_WINTYPES -} wintype; +} wintype_t; typedef enum { WINDOW_SOLID, @@ -204,13 +150,13 @@ typedef enum { typedef struct { unsigned char *data; - int nitems; -} winattr_t; + unsigned long nitems; +} winprop_t; typedef struct _ignore { struct _ignore *next; unsigned long sequence; -} ignore; +} ignore_t; enum wincond_target { CONDTGT_NAME, @@ -238,8 +184,311 @@ typedef struct _wincond { #endif int16_t flags; struct _wincond *next; -} wincond; +} wincond_t; +/// VSync modes. +typedef enum { + VSYNC_NONE, + VSYNC_DRM, + VSYNC_OPENGL, +} vsync_t; + +#ifdef CONFIG_VSYNC_OPENGL +typedef int (*f_WaitVideoSync) (int, int, unsigned *); +typedef int (*f_GetVideoSync) (unsigned *); +#endif + +typedef struct { + int size; + double *data; +} conv; + +struct _win; + +/// Structure representing all options. +typedef struct { + // === General === + char *display; + /// Whether to try to detect WM windows and mark them as focused. + bool mark_wmwin_focused; + /// Whether to mark override-redirect windows as focused. + bool mark_ovredir_focused; + /// Whether to fork to background. + bool fork_after_register; + /// Whether to detect rounded corners. + bool detect_rounded_corners; + /// Whether to paint on X Composite overlay window instead of root + /// window. + bool paint_on_overlay; + /// Whether to unredirect all windows if a full-screen opaque window + /// is detected. + bool unredir_if_possible; + /// Whether to work under synchronized mode for debugging. + bool synchronize; + + // === VSync & software optimization === + /// User-specified refresh rate. + int refresh_rate; + /// Whether to enable refresh-rate-based software optimization. + bool sw_opti; + /// VSync method to use; + vsync_t vsync; + /// Whether to enable double buffer. + bool dbe; + /// Whether to do VSync aggressively. + bool vsync_aggressive; + + // === Shadow === + bool wintype_shadow[NUM_WINTYPES]; + /// Red, green and blue tone of the shadow. + double shadow_red, shadow_green, shadow_blue; + int shadow_radius; + int shadow_offset_x, shadow_offset_y; + double shadow_opacity; + bool clear_shadow; + /// Shadow blacklist. A linked list of conditions. + wincond_t *shadow_blacklist; + /// Whether bounding-shaped window should be ignored. + bool shadow_ignore_shaped; + /// Whether to respect _COMPTON_SHADOW. + bool respect_prop_shadow; + + // === Fading === + bool wintype_fade[NUM_WINTYPES]; + /// How much to fade in in a single fading step. + opacity_t fade_in_step; + /// How much to fade out in a single fading step. + opacity_t fade_out_step; + unsigned long fade_delta; + /// Whether to disable fading on window open/close. + bool no_fading_openclose; + /// Fading blacklist. A linked list of conditions. + wincond_t *fade_blacklist; + + // === Opacity === + double wintype_opacity[NUM_WINTYPES]; + /// Default opacity for inactive windows. + /// 32-bit integer with the format of _NET_WM_OPACITY. 0 stands for + /// not enabled, default. + opacity_t inactive_opacity; + /// Whether inactive_opacity overrides the opacity set by window + /// attributes. + bool inactive_opacity_override; + /// Frame opacity. Relative to window opacity, also affects shadow + /// opacity. + double frame_opacity; + /// Whether to detect _NET_WM_OPACITY on client windows. Used on window + /// managers that don't pass _NET_WM_OPACITY to frame windows. + bool detect_client_opacity; + /// How much to dim an inactive window. 0.0 - 1.0, 0 to disable. + double inactive_dim; + /// Step for pregenerating alpha pictures. 0.01 - 1.0. + double alpha_step; + /// Whether to use EWMH _NET_ACTIVE_WINDOW to find active window. + bool use_ewmh_active_win; + + // === Calculated === + /// Whether compton needs to track focus changes. + bool track_focus; + /// Whether compton needs to track window name and class. + bool track_wdata; + +} options_t; + +/// Structure containing all necessary data for a compton session. +typedef struct { + // === Display related === + /// Display in use. + Display *dpy; + /// Default screen. + int scr; + /// Default visual. + Visual *vis; + /// Default depth. + int depth; + /// Root window. + Window root; + /// Height of root window. + int root_height; + /// Width of root window. + int root_width; + // Damage of root window. + // Damage root_damage; + /// X Composite overlay window. Used if --paint-on-overlay. + Window overlay; + /// Picture of the root window background. + Picture root_tile; + /// A region of the size of the screen. + XserverRegion screen_reg; + /// Picture of root window. Destination of painting in no-DBE painting + /// mode. + Picture root_picture; + /// A Picture acting as the painting target. + Picture tgt_picture; + /// Temporary buffer to paint to before sending to display. + Picture tgt_buffer; + /// DBE back buffer for root window. Used in DBE painting mode. + XdbeBackBuffer root_dbe; + /// Window ID of the window we register as a symbol. + Window reg_win; + + // === Operation related === + /// Program options. + options_t o; + /// Program start time. + struct timeval time_start; + /// The region needs to painted on next paint. + XserverRegion all_damage; + /// Whether all windows are currently redirected. + bool redirected; + /// Whether there's a highest full-screen window, and all windows could + /// be unredirected. + bool unredir_possible; + /// Pre-generated alpha pictures. + Picture *alpha_picts; + /// Whether all reg_ignore of windows should expire in this paint. + bool reg_ignore_expire; + /// Whether the program is idling. I.e. no fading, no potential window + /// changes. + bool idling; + /// Time of last fading. In milliseconds. + unsigned long fade_time; + /// Head pointer of the error ignore linked list. + ignore_t *ignore_head; + /// Pointer to the next member of tail element of the error + /// ignore linked list. + ignore_t **ignore_tail; + /// Reset program after next paint. + bool reset; + + // === Expose event related === + /// Pointer to an array of XRectangle-s of exposed region. + XRectangle *expose_rects; + /// Number of XRectangle-s in expose_rects. + int size_expose; + /// Index of the next free slot in expose_rects. + int n_expose; + + // === Window related === + /// Linked list of all windows. + struct _win *list; + /// Current active window. Used by EWMH _NET_ACTIVE_WINDOW focus + /// detection. + struct _win *active_win; + + // === Shadow/dimming related === + /// 1x1 black Picture. + Picture black_picture; + /// Picture used for dimming inactive windows. + Picture dim_picture; + /// 1x1 Picture of the shadow color. + Picture cshadow_picture; + /// Gaussian map of shadow. + conv *gaussian_map; + // for shadow precomputation + /// Shadow depth on one side. + int cgsize; + /// Pre-computed color table for corners of shadow. + unsigned char *shadow_corner; + /// Pre-computed color table for a side of shadow. + unsigned char *shadow_top; + + // === Software-optimization-related === + /// Currently used refresh rate. + short refresh_rate; + /// Interval between refresh in nanoseconds. + unsigned long refresh_intv; + /// Nanosecond offset of the first painting. + long paint_tm_offset; + + #ifdef CONFIG_VSYNC_DRM + // === DRM VSync related === + /// File descriptor of DRI device file. Used for DRM VSync. + int drm_fd; + #endif + + #ifdef CONFIG_VSYNC_OPENGL + // === OpenGL VSync related === + /// GLX context. + GLXContext glx_context; + /// Pointer to glXGetVideoSyncSGI function. + f_GetVideoSync glx_get_video_sync; + /// Pointer to glXWaitVideoSyncSGI function. + f_WaitVideoSync glx_wait_video_sync; + #endif + + // === X extension related === + /// Event base number for X Fixes extension. + int xfixes_event; + /// Error base number for X Fixes extension. + int xfixes_error; + /// Event base number for X Damage extension. + int damage_event; + /// Error base number for X Damage extension. + int damage_error; + /// Event base number for X Render extension. + int render_event; + /// Error base number for X Render extension. + int render_error; + /// Event base number for X Composite extension. + int composite_event; + /// Error base number for X Composite extension. + int composite_error; + /// Major opcode for X Composite extension. + int composite_opcode; + /// Whether X Composite NameWindowPixmap is available. Aka if X + /// Composite version >= 0.2. + bool has_name_pixmap; + /// Whether X Shape extension exists. + bool shape_exists; + /// Event base number for X Shape extension. + int shape_event; + /// Error base number for X Shape extension. + int shape_error; + /// Whether X RandR extension exists. + bool randr_exists; + /// Event base number for X RandR extension. + int randr_event; + /// Error base number for X RandR extension. + int randr_error; + #ifdef CONFIG_VSYNC_OPENGL + /// Whether X GLX extension exists. + bool glx_exists; + /// Event base number for X GLX extension. + int glx_event; + /// Error base number for X GLX extension. + int glx_error; + #endif + /// Whether X DBE extension exists. + bool dbe_exists; + + // === Atoms === + /// Atom of property _NET_WM_OPACITY. + Atom atom_opacity; + /// Atom of _NET_FRAME_EXTENTS. + Atom atom_frame_extents; + /// Property atom to identify top-level frame window. Currently + /// WM_STATE. + Atom atom_client; + /// Atom of property WM_NAME. + Atom atom_name; + /// Atom of property _NET_WM_NAME. + Atom atom_name_ewmh; + /// Atom of property WM_CLASS. + Atom atom_class; + /// Atom of property WM_TRANSIENT_FOR. + Atom atom_transient; + /// Atom of property _NET_ACTIVE_WINDOW. + Atom atom_ewmh_active_win; + /// Atom of property _COMPTON_SHADOW. + Atom atom_compton_shadow; + /// Atom of property _NET_WM_WINDOW_TYPE. + Atom atom_win_type; + /// Array of atoms of all possible window types. + Atom atoms_wintypes[NUM_WINTYPES]; +} session_t; + +/// Structure representing a top-level window compton manages. typedef struct _win { struct _win *next; Window id; @@ -253,25 +502,26 @@ typedef struct _win { XserverRegion border_size; XserverRegion extents; // Type of the window. - wintype window_type; + wintype_t window_type; /// Whether the window is focused. - Bool focused; - Bool destroyed; + bool focused; + /// Whether the window has been destroyed. + bool destroyed; /// Cached width/height of the window including border. int widthb, heightb; /// Whether the window is bounding-shaped. - Bool bounding_shaped; + bool bounding_shaped; /// Whether the window just have rounded corners. - Bool rounded_corners; - /// Whether this window is to be painted - Bool to_paint; + bool rounded_corners; + /// Whether this window is to be painted. + bool to_paint; // Blacklist related members char *name; char *class_instance; char *class_general; - wincond *cache_sblst; - wincond *cache_fblst; + wincond_t *cache_sblst; + wincond_t *cache_fblst; // Opacity-related members /// Current window opacity. @@ -290,9 +540,9 @@ typedef struct _win { // Fading-related members /// Do not fade if it's false. Change on window type change. /// Used by fading blacklist in the future. - Bool fade; + bool fade; /// Callback to be called after fading completed. - void (*fade_callback) (Display *dpy, struct _win *w); + void (*fade_callback) (session_t *ps, struct _win *w); // Frame-opacity-related members /// Current window frame opacity. Affected by window opacity. @@ -304,7 +554,7 @@ typedef struct _win { // Shadow-related members /// Whether a window has shadow. Affected by window type. - Bool shadow; + bool shadow; /// Opacity of the shadow. Affected by window opacity and frame opacity. double shadow_opacity; /// X offset of shadow. Affected by commandline argument. @@ -325,14 +575,17 @@ typedef struct _win { // Dim-related members /// Whether the window is to be dimmed. - Bool dim; + bool dim; /// Window flags. Definitions above. int_fast16_t flags; unsigned long damage_sequence; /* sequence when damage was created */ - Bool need_configure; + /// Whether there's a pending ConfigureNotify happening + /// when the window is unmapped. + bool need_configure; + /// Queued ConfigureNotify when the window is unmapped. XConfigureEvent queue_configure; /// Region to be ignored when painting. Basically the region where /// higher opaque windows will paint upon. Depends on window frame @@ -343,132 +596,83 @@ typedef struct _win { struct _win *prev_trans; } win; -/// VSync modes. -typedef enum { - VSYNC_NONE, - VSYNC_DRM, - VSYNC_OPENGL, -} vsync_t; - -#ifdef CONFIG_VSYNC_OPENGL -typedef int (*f_WaitVideoSync) (int, int, unsigned *); -typedef int (*f_GetVideoSync) (unsigned *); -#endif - -typedef struct { - // General - char *display; - /// Whether to try to detect WM windows and mark them as focused. - Bool mark_wmwin_focused; - /// Whether to mark override-redirect windows as focused. - Bool mark_ovredir_focused; - /// Whether to fork to background. - Bool fork_after_register; - /// Whether to detect rounded corners. - Bool detect_rounded_corners; - /// Whether to paint on X Composite overlay window instead of root - /// window. - Bool paint_on_overlay; - /// Whether to unredirect all windows if a full-screen opaque window - /// is detected. - Bool unredir_if_possible; - /// Whether to work under synchronized mode for debugging. - Bool synchronize; - - // VSync and software optimization - /// User-specified refresh rate. - int refresh_rate; - /// Whether to enable refresh-rate-based software optimization. - Bool sw_opti; - /// VSync method to use; - vsync_t vsync; - /// Whether to enable double buffer. - Bool dbe; - /// Whether to do VSync aggressively. - Bool vsync_aggressive; - - // Shadow - Bool wintype_shadow[NUM_WINTYPES]; - /// Red, green and blue tone of the shadow. - double shadow_red, shadow_green, shadow_blue; - int shadow_radius; - int shadow_offset_x, shadow_offset_y; - double shadow_opacity; - Bool clear_shadow; - /// Shadow blacklist. A linked list of conditions. - wincond *shadow_blacklist; - /// Whether bounding-shaped window should be ignored. - Bool shadow_ignore_shaped; - /// Whether to respect _COMPTON_SHADOW. - Bool respect_attr_shadow; - - // Fading - Bool wintype_fade[NUM_WINTYPES]; - /// How much to fade in in a single fading step. - opacity_t fade_in_step; - /// How much to fade out in a single fading step. - opacity_t fade_out_step; - unsigned long fade_delta; - Bool no_fading_openclose; - /// Fading blacklist. A linked list of conditions. - wincond *fade_blacklist; - - // Opacity - double wintype_opacity[NUM_WINTYPES]; - /// Default opacity for inactive windows. - /// 32-bit integer with the format of _NET_WM_OPACITY. 0 stands for - /// not enabled, default. - opacity_t inactive_opacity; - /// Whether inactive_opacity overrides the opacity set by window - /// attributes. - Bool inactive_opacity_override; - /// Frame opacity. Relative to window opacity, also affects shadow - /// opacity. - double frame_opacity; - /// Whether to detect _NET_WM_OPACITY on client windows. Used on window - /// managers that don't pass _NET_WM_OPACITY to frame windows. - Bool detect_client_opacity; - /// How much to dim an inactive window. 0.0 - 1.0, 0 to disable. - double inactive_dim; - /// Step for pregenerating alpha pictures. 0.01 - 1.0. - double alpha_step; - /// Whether to use EWMH _NET_ACTIVE_WINDOW to find active window. - Bool use_ewmh_active_win; - - // Calculated - /// Whether compton needs to track focus changes. - Bool track_focus; - /// Whether compton needs to track window name and class. - Bool track_wdata; - -} options_t; - +/// Temporary structure used for communication between +/// get_cfg() and parse_config(). struct options_tmp { - Bool no_dock_shadow; - Bool no_dnd_shadow; + bool no_dock_shadow; + bool no_dnd_shadow; double menu_opacity; }; -typedef struct _conv { - int size; - double *data; -} conv; - typedef enum { WIN_EVMODE_UNKNOWN, WIN_EVMODE_FRAME, WIN_EVMODE_CLIENT } win_evmode_t; -extern int root_height, root_width; -extern Atom atom_client_attr; -extern Bool idling; -extern Bool shape_exists; -extern Bool reg_ignore_expire; +extern const char *WINTYPES[NUM_WINTYPES]; +extern session_t *ps_g; + +// == Debugging code == +static void +print_timestamp(session_t *ps); + +#ifdef DEBUG_ALLOC_REG + +#include +#define BACKTRACE_SIZE 5 /** - * Functions + * Print current backtrace, excluding the first two items. + * + * Stolen from glibc manual. */ +static inline void +print_backtrace(void) { + void *array[BACKTRACE_SIZE]; + size_t size; + char **strings; + + size = backtrace(array, BACKTRACE_SIZE); + strings = backtrace_symbols(array, size); + + for (size_t i = 2; i < size; i++) + printf ("%s\n", strings[i]); + + free(strings); +} + +/** + * Wrapper of XFixesCreateRegion, for debugging. + */ +static inline XserverRegion +XFixesCreateRegion_(Display *dpy, XRectangle *p, int n, + const char *func, int line) { + XserverRegion reg = XFixesCreateRegion(dpy, p, n); + print_timestamp(ps_g); + printf("%#010lx: XFixesCreateRegion() in %s():%d\n", reg, func, line); + print_backtrace(); + fflush(stdout); + return reg; +} + +/** + * Wrapper of XFixesDestroyRegion, for debugging. + */ +static inline void +XFixesDestroyRegion_(Display *dpy, XserverRegion reg, + const char *func, int line) { + XFixesDestroyRegion(dpy, reg); + print_timestamp(ps_g); + printf("%#010lx: XFixesDestroyRegion() in %s():%d\n", reg, func, line); + fflush(stdout); +} + +#define XFixesCreateRegion(dpy, p, n) XFixesCreateRegion_(dpy, p, n, __func__, __LINE__) +#define XFixesDestroyRegion(dpy, reg) XFixesDestroyRegion_(dpy, reg, __func__, __LINE__) +#endif + +// == Functions == // inline functions must be made static to compile correctly under clang: // http://clang.llvm.org/compatibility.html#inline @@ -476,40 +680,45 @@ extern Bool reg_ignore_expire; // Helper functions static void -discard_ignore(Display *dpy, unsigned long sequence); +discard_ignore(session_t *ps, unsigned long sequence); static void -set_ignore(Display *dpy, unsigned long sequence); +set_ignore(session_t *ps, unsigned long sequence); + +static inline void +set_ignore_next(session_t *ps) { + set_ignore(ps, NextRequest(ps->dpy)); +} static int -should_ignore(Display *dpy, unsigned long sequence); +should_ignore(session_t *ps, unsigned long sequence); /** * Subtract two unsigned long values. * * Truncate to 0 if the result is negative. */ -static inline unsigned long +static inline unsigned long __attribute__((const)) sub_unslong(unsigned long a, unsigned long b) { return (a > b) ? a - b : 0; } /** - * Set a Bool array of all wintypes to true. + * Set a bool array of all wintypes to true. */ static void -wintype_arr_enable(Bool arr[]) { - wintype i; +wintype_arr_enable(bool arr[]) { + wintype_t i; for (i = 0; i < NUM_WINTYPES; ++i) { - arr[i] = True; + arr[i] = true; } } /** * Allocate the space and copy a string. */ -static inline char * +static inline char * __attribute__((const)) mstrcpy(const char *src) { char *str = malloc(sizeof(char) * (strlen(src) + 1)); @@ -521,7 +730,7 @@ mstrcpy(const char *src) { /** * Allocate the space and join two strings. */ -static inline char * +static inline char * __attribute__((const)) mstrjoin(const char *src1, const char *src2) { char *str = malloc(sizeof(char) * (strlen(src1) + strlen(src2) + 1)); @@ -534,7 +743,7 @@ mstrjoin(const char *src1, const char *src2) { /** * Allocate the space and join two strings; */ -static inline char * +static inline char * __attribute__((const)) mstrjoin3(const char *src1, const char *src2, const char *src3) { char *str = malloc(sizeof(char) * (strlen(src1) + strlen(src2) + strlen(src3) + 1)); @@ -554,7 +763,7 @@ mstrjoin3(const char *src1, const char *src2, const char *src3) { * @param max maximum value * @return normalized value */ -static inline int +static inline int __attribute__((const)) normalize_i_range(int i, int min, int max) { if (i > max) return max; if (i < min) return min; @@ -564,7 +773,7 @@ normalize_i_range(int i, int min, int max) { /** * Select the larger integer of two. */ -static inline int +static inline int __attribute__((const)) max_i(int a, int b) { return (a > b ? a : b); } @@ -572,7 +781,7 @@ max_i(int a, int b) { /** * Select the smaller integer of two. */ -static inline int +static inline int __attribute__((const)) min_i(int a, int b) { return (a > b ? b : a); } @@ -585,7 +794,7 @@ min_i(int a, int b) { * @param max maximum value * @return normalized value */ -static inline double +static inline double __attribute__((const)) normalize_d_range(double d, double min, double max) { if (d > max) return max; if (d < min) return min; @@ -598,7 +807,7 @@ normalize_d_range(double d, double min, double max) { * @param d double value to normalize * @return normalized value */ -static inline double +static inline double __attribute__((const)) normalize_d(double d) { return normalize_d_range(d, 0.0, 1.0); } @@ -610,15 +819,15 @@ normalize_d(double d) { * @param count amount of elements in the array * @param wid window ID to search for */ -static inline Bool +static inline bool array_wid_exists(const Window *arr, int count, Window wid) { while (count--) { if (arr[count] == wid) { - return True; + return true; } } - return False; + return false; } /* @@ -695,9 +904,9 @@ timespec_subtract(struct timespec *result, * * Note its starting time is unspecified. */ -static inline struct timespec +static inline struct timespec __attribute__((const)) get_time_timespec(void) { - struct timespec tm = { 0 }; + struct timespec tm = { 0, 0 }; clock_gettime(CLOCK_MONOTONIC, &tm); @@ -711,12 +920,12 @@ get_time_timespec(void) { * Used for debugging. */ static void -print_timestamp(void) { +print_timestamp(session_t *ps) { struct timeval tm, diff; if (gettimeofday(&tm, NULL)) return; - timeval_subtract(&diff, &tm, &time_start); + timeval_subtract(&diff, &tm, &ps->time_start); printf("[ %5ld.%02ld ] ", diff.tv_sec, diff.tv_usec / 10000); } @@ -724,9 +933,9 @@ print_timestamp(void) { * Destroy a XserverRegion. */ inline static void -free_region(Display *dpy, XserverRegion *p) { +free_region(session_t *ps, XserverRegion *p) { if (*p) { - XFixesDestroyRegion(dpy, *p); + XFixesDestroyRegion(ps->dpy, *p); *p = None; } } @@ -735,9 +944,9 @@ free_region(Display *dpy, XserverRegion *p) { * Destroy a Picture. */ inline static void -free_picture(Display *dpy, Picture *p) { +free_picture(session_t *ps, Picture *p) { if (*p) { - XRenderFreePicture(dpy, *p); + XRenderFreePicture(ps->dpy, *p); *p = None; } } @@ -746,9 +955,9 @@ free_picture(Display *dpy, Picture *p) { * Destroy a Pixmap. */ inline static void -free_pixmap(Display *dpy, Pixmap *p) { +free_pixmap(session_t *ps, Pixmap *p) { if (*p) { - XFreePixmap(dpy, *p); + XFreePixmap(ps->dpy, *p); *p = None; } } @@ -757,15 +966,64 @@ free_pixmap(Display *dpy, Pixmap *p) { * Destroy a Damage. */ inline static void -free_damage(Display *dpy, Damage *p) { +free_damage(session_t *ps, Damage *p) { if (*p) { // BadDamage will be thrown if the window is destroyed - set_ignore(dpy, NextRequest(dpy)); - XDamageDestroy(dpy, *p); + set_ignore_next(ps); + XDamageDestroy(ps->dpy, *p); *p = None; } } +/** + * Destroy a wincond_t. + */ +inline static void +free_wincond(wincond_t *cond) { + if (cond->pattern) + free(cond->pattern); +#ifdef CONFIG_REGEX_PCRE + if (cond->regex_pcre_extra) + pcre_free_study(cond->regex_pcre_extra); + if (cond->regex_pcre) + pcre_free(cond->regex_pcre); +#endif + free(cond); +} + +/** + * Destroy a linked list of wincond_t. + */ +inline static void +free_wincondlst(wincond_t **cond_lst) { + wincond_t *next = NULL; + + for (wincond_t *cond = *cond_lst; cond; cond = next) { + next = cond->next; + + free_wincond(cond); + } + + *cond_lst = NULL; +} + +/** + * Destroy all resources in a struct _win. + */ +inline static void +free_win_res(session_t *ps, win *w) { + free_region(ps, &w->extents); + free_pixmap(ps, &w->pixmap); + free_picture(ps, &w->picture); + free_region(ps, &w->border_size); + free_picture(ps, &w->shadow_pict); + free_damage(ps, &w->damage); + free_region(ps, &w->reg_ignore); + free(w->name); + free(w->class_instance); + free(w->class_general); +} + /** * Get current system clock in milliseconds. * @@ -782,53 +1040,51 @@ get_time_ms(void) { } static int -fade_timeout(void); +fade_timeout(session_t *ps); static void -run_fade(Display *dpy, win *w, unsigned steps); +run_fade(session_t *ps, win *w, unsigned steps); static void -set_fade_callback(Display *dpy, win *w, - void (*callback) (Display *dpy, win *w), Bool exec_callback); +set_fade_callback(session_t *ps, win *w, + void (*callback) (session_t *ps, win *w), bool exec_callback); /** * Execute fade callback of a window if fading finished. */ static inline void -check_fade_fin(Display *dpy, win *w) { +check_fade_fin(session_t *ps, win *w) { if (w->fade_callback && w->opacity == w->opacity_tgt) { // Must be the last line as the callback could destroy w! - set_fade_callback(dpy, w, NULL, True); + set_fade_callback(ps, w, NULL, true); } } static void -set_fade_callback(Display *dpy, win *w, - void (*callback) (Display *dpy, win *w), Bool exec_callback); +set_fade_callback(session_t *ps, win *w, + void (*callback) (session_t *ps, win *w), bool exec_callback); static double gaussian(double r, double x, double y); static conv * -make_gaussian_map(Display *dpy, double r); +make_gaussian_map(double r); static unsigned char sum_gaussian(conv *map, double opacity, int x, int y, int width, int height); static void -presum_gaussian(conv *map); +presum_gaussian(session_t *ps, conv *map); static XImage * -make_shadow(Display *dpy, double opacity, - int width, int height, Bool clear_shadow); +make_shadow(session_t *ps, double opacity, int width, int height); static Picture -shadow_picture(Display *dpy, double opacity, int width, int height, - Bool clear_shadow); +shadow_picture(session_t *ps, double opacity, int width, int height); static Picture -solid_picture(Display *dpy, Bool argb, double a, +solid_picture(session_t *ps, bool argb, double a, double r, double g, double b); static inline bool is_normal_win(const win *w) { @@ -839,25 +1095,25 @@ static inline bool is_normal_win(const win *w) { /** * Determine if a window has a specific attribute. * - * @param dpy Display to use + * @param session_t current session * @param w window to check * @param atom atom of attribute to check * @return 1 if it has the attribute, 0 otherwise */ -static inline Bool -wid_has_attr(Display *dpy, Window w, Atom atom) { +static inline bool +wid_has_attr(const session_t *ps, Window w, Atom atom) { Atom type = None; int format; unsigned long nitems, after; unsigned char *data; - if (Success == XGetWindowProperty(dpy, w, atom, 0, 0, False, + if (Success == XGetWindowProperty(ps->dpy, w, atom, 0, 0, False, AnyPropertyType, &type, &format, &nitems, &after, &data)) { XFree(data); - if (type) return True; + if (type) return true; } - return False; + return false; } /** @@ -866,17 +1122,17 @@ wid_has_attr(Display *dpy, Window w, Atom atom) { * Returns a blank structure if the returned type and format does not * match the requested type and format. * - * @param dpy Display to use + * @param session_t current session * @param w window * @param atom atom of attribute to fetch * @param length length to read * @param rtype atom of the requested type * @param rformat requested format - * @return a winattr_t structure containing the attribute + * @return a winprop_t structure containing the attribute * and number of items. A blank one on failure. */ -static winattr_t -wid_get_attr(Display *dpy, Window w, Atom atom, long length, +static winprop_t +wid_get_prop(const session_t *ps, Window w, Atom atom, long length, Atom rtype, int rformat) { Atom type = None; int format = 0; @@ -884,10 +1140,10 @@ wid_get_attr(Display *dpy, Window w, Atom atom, long length, unsigned char *data = NULL; // Use two if statements to deal with the sequence point issue. - if (Success == XGetWindowProperty(dpy, w, atom, 0L, length, False, + if (Success == XGetWindowProperty(ps->dpy, w, atom, 0L, length, False, rtype, &type, &format, &nitems, &after, &data)) { if (type == rtype && format == rformat) { - return (winattr_t) { + return (winprop_t) { .data = data, .nitems = nitems }; @@ -896,83 +1152,102 @@ wid_get_attr(Display *dpy, Window w, Atom atom, long length, XFree(data); - return (winattr_t) { + return (winprop_t) { .data = NULL, .nitems = 0 }; } /** - * Free a winattr_t. + * Free a winprop_t. * - * @param pattr pointer to the winattr_t to free. + * @param pprop pointer to the winprop_t to free. */ static inline void -free_winattr(winattr_t *pattr) { +free_winprop(winprop_t *pprop) { // Empty the whole structure to avoid possible issues - if (pattr->data) { - XFree(pattr->data); - pattr->data = NULL; + if (pprop->data) { + XFree(pprop->data); + pprop->data = NULL; + } + pprop->nitems = 0; +} + +/** + * Stop listening for events on a particular window. + */ +static inline void +win_ev_stop(session_t *ps, win *w) { + // Will get BadWindow if the window is destroyed + set_ignore_next(ps); + XSelectInput(ps->dpy, w->id, 0); + + if (w->client_win) { + set_ignore_next(ps); + XSelectInput(ps->dpy, w->client_win, 0); + } + + if (ps->shape_exists) { + set_ignore_next(ps); + XShapeSelectInput(ps->dpy, w->id, 0); } - pattr->nitems = 0; } /** * Get the children of a window. * - * @param dpy Display to use + * @param session_t current session * @param w window to check * @param children [out] an array of child window IDs * @param nchildren [out] number of children * @return 1 if successful, 0 otherwise */ -static inline Bool -wid_get_children(Display *dpy, Window w, +static inline bool +wid_get_children(session_t *ps, Window w, Window **children, unsigned *nchildren) { Window troot, tparent; - if (!XQueryTree(dpy, w, &troot, &tparent, children, nchildren)) { + if (!XQueryTree(ps->dpy, w, &troot, &tparent, children, nchildren)) { *nchildren = 0; - return False; + return false; } - return True; + return true; } /** * Check if a window is bounding-shaped. */ -static inline Bool -wid_bounding_shaped(Display *dpy, Window wid) { - if (shape_exists) { - Bool bounding_shaped = False; - Bool clip_shaped; +static inline bool +wid_bounding_shaped(const session_t *ps, Window wid) { + if (ps->shape_exists) { + Bool bounding_shaped = False, clip_shaped = False; int x_bounding, y_bounding, x_clip, y_clip; unsigned int w_bounding, h_bounding, w_clip, h_clip; - XShapeQueryExtents(dpy, wid, &bounding_shaped, + XShapeQueryExtents(ps->dpy, wid, &bounding_shaped, &x_bounding, &y_bounding, &w_bounding, &h_bounding, &clip_shaped, &x_clip, &y_clip, &w_clip, &h_clip); return bounding_shaped; } - - return False; + + return false; } /** - * Determine if a window change affects reg_ignore and set - * reg_ignore_expire accordingly. + * Determine if a window change affects reg_ignore and set + * reg_ignore_expire accordingly. */ static inline void -update_reg_ignore_expire(const win *w) { +update_reg_ignore_expire(session_t *ps, const win *w) { if (w->to_paint && WINDOW_SOLID == w->mode) - reg_ignore_expire = True; + ps->reg_ignore_expire = true; } /** * Check whether a window has WM frames. */ -static inline bool +static inline bool __attribute__((const)) win_has_frame(const win *w) { return w->top_width || w->left_width || w->right_width || w->bottom_width; @@ -984,261 +1259,261 @@ win_has_frame(const win *w) { * It's not using w->border_size for performance measures. */ static inline bool -win_is_fullscreen(const win *w) { - return (w->a.x <= 0 && w->a.y <= 0 && (w->a.x + w->widthb) >= root_width - && (w->a.y + w->heightb) >= root_height && !w->bounding_shaped); +win_is_fullscreen(session_t *ps, const win *w) { + return (w->a.x <= 0 && w->a.y <= 0 + && (w->a.x + w->widthb) >= ps->root_width + && (w->a.y + w->heightb) >= ps->root_height + && !w->bounding_shaped); } static void -win_rounded_corners(Display *dpy, win *w); +win_rounded_corners(session_t *ps, win *w); static bool -win_match_once(win *w, const wincond *cond); +win_match_once(win *w, const wincond_t *cond); static bool -win_match(win *w, wincond *condlst, wincond * *cache); +win_match(win *w, wincond_t *condlst, wincond_t * *cache); -static Bool -condlst_add(wincond **pcondlst, const char *pattern); +static bool +condlst_add(wincond_t **pcondlst, const char *pattern); static long -determine_evmask(Display *dpy, Window wid, win_evmode_t mode); +determine_evmask(session_t *ps, Window wid, win_evmode_t mode); static win * -find_win(Window id); +find_win(session_t *ps, Window id); static win * -find_toplevel(Window id); +find_toplevel(session_t *ps, Window id); static win * -find_toplevel2(Display *dpy, Window wid); +find_toplevel2(session_t *ps, Window wid); static win * -recheck_focus(Display *dpy); +recheck_focus(session_t *ps); static Picture -root_tile_f(Display *dpy); +root_tile_f(session_t *ps); static void -paint_root(Display *dpy); +paint_root(session_t *ps, Picture tgt_buffer); static XserverRegion -win_extents(Display *dpy, win *w); +win_extents(session_t *ps, win *w); static XserverRegion -border_size(Display *dpy, win *w); +border_size(session_t *ps, win *w); static Window -find_client_win(Display *dpy, Window w); +find_client_win(session_t *ps, Window w); static void -get_frame_extents(Display *dpy, win *w, Window client); +get_frame_extents(session_t *ps, win *w, Window client); static win * -paint_preprocess(Display *dpy, win *list); +paint_preprocess(session_t *ps, win *list); static void -paint_all(Display *dpy, XserverRegion region, win *t); +paint_all(session_t *ps, XserverRegion region, win *t); static void -add_damage(Display *dpy, XserverRegion damage); +add_damage(session_t *ps, XserverRegion damage); static void -repair_win(Display *dpy, win *w); +repair_win(session_t *ps, win *w); -static wintype -get_wintype_prop(Display * dpy, Window w); +static wintype_t +wid_get_prop_wintype(session_t *ps, Window w); static void -map_win(Display *dpy, Window id, - unsigned long sequence, Bool fade, - Bool override_redirect); +map_win(session_t *ps, Window id, bool override_redirect); static void -finish_map_win(Display *dpy, win *w); +finish_map_win(session_t *ps, win *w); static void -finish_unmap_win(Display *dpy, win *w); +finish_unmap_win(session_t *ps, win *w); static void -unmap_callback(Display *dpy, win *w); +unmap_callback(session_t *ps, win *w); static void -unmap_win(Display *dpy, Window id, Bool fade); +unmap_win(session_t *ps, Window id); static opacity_t -wid_get_opacity_prop(Display *dpy, Window wid, opacity_t def); +wid_get_opacity_prop(session_t *ps, Window wid, opacity_t def); static double -get_opacity_percent(Display *dpy, win *w); +get_opacity_percent(win *w); static void -determine_mode(Display *dpy, win *w); +determine_mode(session_t *ps, win *w); static void -calc_opacity(Display *dpy, win *w, Bool refetch_prop); +calc_opacity(session_t *ps, win *w, bool refetch_prop); static void -calc_dim(Display *dpy, win *w); +calc_dim(session_t *ps, win *w); static inline void -set_focused(Display *dpy, win *w, Bool focused) { +set_focused(session_t *ps, win *w, bool focused) { w->focused = focused; - calc_opacity(dpy, w, False); - calc_dim(dpy, w); + calc_opacity(ps, w, false); + calc_dim(ps, w); } static void -determine_fade(Display *dpy, win *w); +determine_fade(session_t *ps, win *w); static void -win_update_shape_raw(Display *dpy, win *w); +win_update_shape_raw(session_t *ps, win *w); static void -win_update_shape(Display *dpy, win *w); +win_update_shape(session_t *ps, win *w); static void -win_update_attr_shadow_raw(Display *dpy, win *w); +win_update_attr_shadow_raw(session_t *ps, win *w); static void -win_update_attr_shadow(Display *dpy, win *w); +win_update_attr_shadow(session_t *ps, win *w); static void -determine_shadow(Display *dpy, win *w); +determine_shadow(session_t *ps, win *w); static void -calc_win_size(Display *dpy, win *w); +calc_win_size(session_t *ps, win *w); static void -calc_shadow_geometry(Display *dpy, win *w); +calc_shadow_geometry(session_t *ps, win *w); static void -mark_client_win(Display *dpy, win *w, Window client); +mark_client_win(session_t *ps, win *w, Window client); static void -add_win(Display *dpy, Window id, Window prev, Bool override_redirect); +add_win(session_t *ps, Window id, Window prev, bool override_redirect); static void -restack_win(Display *dpy, win *w, Window new_above); +restack_win(session_t *ps, win *w, Window new_above); static void -configure_win(Display *dpy, XConfigureEvent *ce); +configure_win(session_t *ps, XConfigureEvent *ce); static void -circulate_win(Display *dpy, XCirculateEvent *ce); +circulate_win(session_t *ps, XCirculateEvent *ce); static void -finish_destroy_win(Display *dpy, Window id); +finish_destroy_win(session_t *ps, Window id); static void -destroy_callback(Display *dpy, win *w); +destroy_callback(session_t *ps, win *w); static void -destroy_win(Display *dpy, Window id, Bool fade); +destroy_win(session_t *ps, Window id); static void -damage_win(Display *dpy, XDamageNotifyEvent *de); +damage_win(session_t *ps, XDamageNotifyEvent *de); static int error(Display *dpy, XErrorEvent *ev); static void -expose_root(Display *dpy, XRectangle *rects, int nrects); +expose_root(session_t *ps, XRectangle *rects, int nrects); -static Bool -wid_get_text_prop(Display *dpy, Window wid, Atom prop, +static bool +wid_get_text_prop(session_t *ps, Window wid, Atom prop, char ***pstrlst, int *pnstr); -static Bool -wid_get_name(Display *dpy, Window w, char **name); +static bool +wid_get_name(session_t *ps, Window w, char **name); static int -win_get_name(Display *dpy, win *w); +win_get_name(session_t *ps, win *w); -static Bool -win_get_class(Display *dpy, win *w); +static bool +win_get_class(session_t *ps, win *w); #ifdef DEBUG_EVENTS static int ev_serial(XEvent *ev); static const char * -ev_name(XEvent *ev); +ev_name(session_t *ps, XEvent *ev); static Window -ev_window(XEvent *ev); +ev_window(session_t *ps, XEvent *ev); #endif -static void +static void __attribute__ ((noreturn)) usage(void); static void -register_cm(Bool want_glxct); +register_cm(session_t *ps, bool want_glxct); inline static void -ev_focus_in(XFocusChangeEvent *ev); +ev_focus_in(session_t *ps, XFocusChangeEvent *ev); inline static void -ev_focus_out(XFocusChangeEvent *ev); +ev_focus_out(session_t *ps, XFocusChangeEvent *ev); inline static void -ev_create_notify(XCreateWindowEvent *ev); +ev_create_notify(session_t *ps, XCreateWindowEvent *ev); inline static void -ev_configure_notify(XConfigureEvent *ev); +ev_configure_notify(session_t *ps, XConfigureEvent *ev); inline static void -ev_destroy_notify(XDestroyWindowEvent *ev); +ev_destroy_notify(session_t *ps, XDestroyWindowEvent *ev); inline static void -ev_map_notify(XMapEvent *ev); +ev_map_notify(session_t *ps, XMapEvent *ev); inline static void -ev_unmap_notify(XUnmapEvent *ev); +ev_unmap_notify(session_t *ps, XUnmapEvent *ev); inline static void -ev_reparent_notify(XReparentEvent *ev); +ev_reparent_notify(session_t *ps, XReparentEvent *ev); inline static void -ev_circulate_notify(XCirculateEvent *ev); +ev_circulate_notify(session_t *ps, XCirculateEvent *ev); inline static void -ev_expose(XExposeEvent *ev); +ev_expose(session_t *ps, XExposeEvent *ev); static void -update_ewmh_active_win(Display *dpy); +update_ewmh_active_win(session_t *ps); inline static void -ev_property_notify(XPropertyEvent *ev); +ev_property_notify(session_t *ps, XPropertyEvent *ev); inline static void -ev_damage_notify(XDamageNotifyEvent *ev); +ev_damage_notify(session_t *ps, XDamageNotifyEvent *ev); inline static void -ev_shape_notify(XShapeEvent *ev); +ev_shape_notify(session_t *ps, XShapeEvent *ev); /** * Get a region of the screen size. */ inline static XserverRegion -get_screen_region(Display *dpy) { +get_screen_region(session_t *ps) { XRectangle r; r.x = 0; r.y = 0; - r.width = root_width; - r.height = root_height; - return XFixesCreateRegion(dpy, &r, 1); + r.width = ps->root_width; + r.height = ps->root_height; + return XFixesCreateRegion(ps->dpy, &r, 1); } /** * Copies a region */ inline static XserverRegion -copy_region(Display *dpy, XserverRegion oldregion) { - XserverRegion region = XFixesCreateRegion(dpy, NULL, 0); +copy_region(const session_t *ps, XserverRegion oldregion) { + XserverRegion region = XFixesCreateRegion(ps->dpy, NULL, 0); - XFixesCopyRegion(dpy, region, oldregion); + XFixesCopyRegion(ps->dpy, region, oldregion); return region; } @@ -1247,9 +1522,9 @@ copy_region(Display *dpy, XserverRegion oldregion) { * Dump a region. */ static inline void -dump_region(Display *dpy, XserverRegion region) { +dump_region(const session_t *ps, XserverRegion region) { int nrects = 0, i; - XRectangle *rects = XFixesFetchRegion(dpy, region, &nrects); + XRectangle *rects = XFixesFetchRegion(ps->dpy, region, &nrects); if (!rects) return; @@ -1265,11 +1540,14 @@ dump_region(Display *dpy, XserverRegion region) { * * Keith Packard said this is slow: * http://lists.freedesktop.org/archives/xorg/2007-November/030467.html + * + * @param ps current session + * @param region region to check for */ -static inline Bool -is_region_empty(Display *dpy, XserverRegion region) { +static inline bool +is_region_empty(const session_t *ps, XserverRegion region) { int nrects = 0; - XRectangle *rects = XFixesFetchRegion(dpy, region, &nrects); + XRectangle *rects = XFixesFetchRegion(ps->dpy, region, &nrects); XFree(rects); @@ -1279,36 +1557,49 @@ is_region_empty(Display *dpy, XserverRegion region) { /** * Add a window to damaged area. * - * @param dpy display in use + * @param ps current session * @param w struct _win element representing the window */ static inline void -add_damage_win(Display *dpy, win *w) { +add_damage_win(session_t *ps, win *w) { if (w->extents) { - add_damage(dpy, copy_region(dpy, w->extents)); + add_damage(ps, copy_region(ps, w->extents)); } } #if defined(DEBUG_EVENTS) || defined(DEBUG_RESTACK) static bool -ev_window_name(Display *dpy, Window wid, char **name); +ev_window_name(session_t *ps, Window wid, char **name); #endif inline static void -ev_handle(XEvent *ev); +ev_handle(session_t *ps, XEvent *ev); static void fork_after(void); #ifdef CONFIG_LIBCONFIG +/** + * Wrapper of libconfig's config_lookup_int. + * + * To convert int value config_lookup_bool + * returns to bool. + */ static inline void -lcfg_lookup_bool(const config_t *config, const char *path, Bool *value) { +lcfg_lookup_bool(const config_t *config, const char *path, + bool *value) { int ival; if (config_lookup_bool(config, path, &ival)) *value = ival; } +/** + * Wrapper of libconfig's config_lookup_int. + * + * To deal with the different value types config_lookup_int + * returns in libconfig-1.3 and libconfig-1.4. + */ static inline int lcfg_lookup_int(const config_t *config, const char *path, int *value) { #ifndef CONFIG_LIBCONFIG_LEGACY @@ -1328,54 +1619,66 @@ static FILE * open_config_file(char *cpath, char **path); static void -parse_config(char *cpath, struct options_tmp *pcfgtmp); +parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp); #endif static void -get_cfg(int argc, char *const *argv); +get_cfg(session_t *ps, int argc, char *const *argv); static void -get_atoms(void); +init_atoms(session_t *ps); static void -update_refresh_rate(Display *dpy); +update_refresh_rate(session_t *ps); -static Bool -sw_opti_init(void); +static bool +sw_opti_init(session_t *ps); static int -evpoll(struct pollfd *fd, int timeout); +evpoll(session_t *ps, int timeout); -static Bool -vsync_drm_init(void); +static bool +vsync_drm_init(session_t *ps); #ifdef CONFIG_VSYNC_DRM static int -vsync_drm_wait(void); +vsync_drm_wait(session_t *ps); #endif -static Bool -vsync_opengl_init(void); +static bool +vsync_opengl_init(session_t *ps); #ifdef CONFIG_VSYNC_OPENGL static void -vsync_opengl_wait(void); +vsync_opengl_wait(session_t *ps); #endif static void -vsync_wait(void); +vsync_wait(session_t *ps); static void -init_alpha_picts(Display *dpy); +init_alpha_picts(session_t *ps); static void -init_dbe(void); +init_dbe(session_t *ps); static void -init_overlay(void); +init_overlay(session_t *ps); static void -redir_start(Display *dpy); +redir_start(session_t *ps); static void -redir_stop(Display *dpy); +redir_stop(session_t *ps); + +static session_t * +session_init(session_t *ps_old, int argc, char **argv); + +static void +session_destroy(session_t *ps); + +static void +session_run(session_t *ps); + +static void +reset_enable(int __attribute__((unused)) signum);