From: Simon McVittie Date: Fri, 5 Nov 2021 09:59:55 +0000 (+0000) Subject: New upstream version 4.4.1+ds1 X-Git-Tag: archive/raspbian/4.4.1+ds1-2+rpi1^2~18^2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=ab14b59380d6a3260433656372a6169ee3870fdb;p=gtk4.git New upstream version 4.4.1+ds1 --- ab14b59380d6a3260433656372a6169ee3870fdb diff --cc gtk/theme/Default/Default-dark.css index 2598668393,0000000000..5ee5ec845b mode 100644,000000..100644 --- a/gtk/theme/Default/Default-dark.css +++ b/gtk/theme/Default/Default-dark.css @@@ -1,1858 -1,0 +1,1848 @@@ +/*************************** Check and Radio buttons * */ +/*************** Base States * */ +.background { color: #eeeeec; background-color: #353535; } + +.background:backdrop { text-shadow: none; -gtk-icon-shadow: none; } + +dnd { color: #eeeeec; } + +.normal-icons { -gtk-icon-size: 16px; } + +.large-icons { -gtk-icon-size: 32px; } + +image:disabled { -gtk-icon-filter: opacity(0.5); } + +.view, iconview, textview > text { color: white; background-color: #2d2d2d; } + +.view:disabled, iconview:disabled, textview > text:disabled { color: #919190; background-color: #323232; } + +.view:selected:focus, iconview:selected:focus, .view:selected, iconview:selected, textview > text:selected:focus, textview > text:selected { border-radius: 3px; } + +textview:drop(active) { caret-color: #26a269; } + +textview > border { background-color: #313131; } + +iconview { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +iconview { outline: 0 solid transparent; outline-offset: 4px; } + +iconview:focus:focus-visible { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: -2px; } + +iconview:drop(active) { box-shadow: none; } + +iconview > dndtarget:drop(active) { border-style: solid; border-width: 1px; border-color: #030c17; } + +rubberband, .content-view > rubberband, columnview.view > rubberband, treeview.view > rubberband, gridview > rubberband, flowbox > rubberband { border: 1px solid #0f3b71; background-color: rgba(15, 59, 113, 0.2); } + +flowbox > flowboxchild { padding: 3px; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +flowbox > flowboxchild { outline: 0 solid transparent; outline-offset: 4px; } + +flowbox > flowboxchild:focus:focus-visible { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: -2px; } + +flowbox > flowboxchild:selected { outline-color: rgba(255, 255, 255, 0.3); } + +gridview > child { padding: 3px; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +gridview > child { outline: 0 solid transparent; outline-offset: 4px; } + +gridview > child:focus:focus-visible { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: -2px; } + +gridview > child:selected { outline-color: rgba(255, 255, 255, 0.3); } + +gridview > child box { border-spacing: 8px; margin: 12px; } + +coverflow cover { color: white; background-color: #2d2d2d; border: 1px solid black; } + +label { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +label { outline: 0 solid transparent; outline-offset: 4px; } + +label:focus:focus-visible { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: -2px; } + +label > selection { background-color: #15539e; color: #ffffff; } + +label:disabled { color: #919190; } + +button label:disabled { color: inherit; } + +label.error { color: #cc0000; } + +label.error:disabled { color: rgba(204, 0, 0, 0.5); } + +.dim-label, .titlebar:not(headerbar) .subtitle, headerbar .subtitle, spinbutton.vertical > text > text > placeholder, spinbutton:not(.vertical) > text > placeholder, entry > text > placeholder, label.separator { opacity: 0.55; text-shadow: none; } + +window.assistant .sidebar { padding: 5px; border-top: 1px solid #1b1b1b; } + +window.assistant.csd .sidebar { border-top-style: none; } + +window.assistant .sidebar > label { padding: 6px 12px; } + +window.assistant .sidebar > label.highlight { background-color: #202020; border-radius: 5px; } + +window.aboutdialog image.large-icons { -gtk-icon-size: 128px; } + +.osd .scale-popup, .app-notification, .osd popover.background > arrow, .osd popover.background > contents, popover.background.touch-selection > arrow, popover.background.touch-selection > contents, popover.background.magnifier > arrow, popover.background.magnifier > contents, .osd { color: #eeeeec; border: none; background-color: rgba(38, 38, 38, 0.7); background-clip: padding-box; -gtk-icon-shadow: 0 1px black; } + +/********************* Spinner Animation * */ +@keyframes spin { to { transform: rotate(1turn); } } + +spinner { background: none; opacity: 0; -gtk-icon-source: -gtk-icontheme("process-working-symbolic"); } + +spinner:checked { opacity: 1; animation: spin 1s linear infinite; } + +spinner:checked:disabled { opacity: 0.5; } + +/********************** General Typography * */ +.large-title { font-weight: 300; font-size: 24pt; } + +.title-1 { font-weight: 800; font-size: 20pt; } + +.title-2 { font-weight: 800; font-size: 15pt; } + +.title-3 { font-weight: 700; font-size: 15pt; } + +.title-4 { font-weight: 700; font-size: 13pt; } + +.heading { font-weight: 700; font-size: 11pt; } + +.body { font-weight: 400; font-size: 11pt; } + +.caption-heading { font-weight: 700; font-size: 9pt; } + +.caption { font-weight: 400; font-size: 9pt; } + +/**************** Text Entries * */ +spinbutton.vertical > text, spinbutton:not(.vertical), entry { min-height: 32px; padding-left: 8px; padding-right: 8px; border: 1px solid; border-radius: 5px; border-spacing: 6px; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); color: white; border-color: #1b1b1b; background-color: #2d2d2d; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +spinbutton.vertical > text, spinbutton:not(.vertical), entry { outline: 0 solid transparent; outline-offset: 4px; } + +spinbutton.vertical > text:focus-within, spinbutton:focus-within:not(.vertical), entry:focus-within { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: -2px; } + +spinbutton.vertical > text > image.left, spinbutton:not(.vertical) > image.left, entry > image.left { margin-right: 6px; } + +spinbutton.vertical > text > image.right, spinbutton:not(.vertical) > image.right, entry > image.right { margin-left: 6px; } + +spinbutton.vertical > text > text > block-cursor, spinbutton:not(.vertical) > text > block-cursor, entry > text > block-cursor { color: #2d2d2d; background-color: white; } + +spinbutton.vertical > text.flat, spinbutton.flat:not(.vertical), entry.flat:focus-within, entry.flat:backdrop, entry.flat:disabled, entry.flat { min-height: 0; padding: 2px; background-color: transparent; border-color: transparent; border-radius: 0; } + +spinbutton.vertical > text:focus-within > placeholder, spinbutton:focus-within:not(.vertical) > placeholder, entry:focus-within > placeholder { opacity: 0; /* We hide placeholders on focus */ } + +spinbutton.vertical > text:disabled, spinbutton:disabled:not(.vertical), entry:disabled { color: #919190; border-color: #1b1b1b; background-color: #323232; } + +spinbutton.vertical > text.error, spinbutton.error:not(.vertical), entry.error { color: #cc0000; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +spinbutton.vertical > text.error, spinbutton.error:not(.vertical), entry.error { outline: 0 solid transparent; outline-offset: 4px; } + +spinbutton.vertical > text.error:focus-within, spinbutton.error:focus-within:not(.vertical), entry.error:focus-within { outline-color: rgba(204, 0, 0, 0.5); outline-width: 2px; outline-offset: -2px; } + +spinbutton.vertical > text.error > selection, spinbutton.error:not(.vertical) > selection, entry.error > selection { background-color: #cc0000; } + +spinbutton.vertical > text.warning, spinbutton.warning:not(.vertical), entry.warning { color: #f57900; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +spinbutton.vertical > text.warning, spinbutton.warning:not(.vertical), entry.warning { outline: 0 solid transparent; outline-offset: 4px; } + +spinbutton.vertical > text.warning:focus-within, spinbutton.warning:focus-within:not(.vertical), entry.warning:focus-within { outline-color: rgba(245, 121, 0, 0.5); outline-width: 2px; outline-offset: -2px; } + +spinbutton.vertical > text.warning > selection, spinbutton.warning:not(.vertical) > selection, entry.warning > selection { background-color: #f57900; } + +spinbutton.vertical > text > image, spinbutton:not(.vertical) > image, entry > image { color: #c7c7c6; } + +spinbutton.vertical > text > image:hover, spinbutton:not(.vertical) > image:hover, entry > image:hover { color: #eeeeec; } + +spinbutton.vertical > text > image:active, spinbutton:not(.vertical) > image:active, entry > image:active { color: #15539e; } + +spinbutton.vertical > text.password image.caps-lock-indicator, spinbutton.password:not(.vertical) image.caps-lock-indicator, entry.password image.caps-lock-indicator { color: #7e7e7d; } + +spinbutton.vertical > text:drop(active), spinbutton:drop(active):not(.vertical), entry:drop(active):focus-within, entry:drop(active) { border-color: #26a269; box-shadow: inset 0 0 0 1px #26a269; } + +.osd spinbutton.vertical > text, .osd spinbutton:not(.vertical), .osd entry { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: rgba(0, 0, 0, 0.5); background-clip: padding-box; box-shadow: none; -gtk-icon-shadow: 0 1px black; } + +.osd spinbutton.vertical > text:focus-within, .osd spinbutton:focus-within:not(.vertical), .osd entry:focus-within { color: white; border-color: #15539e; background-color: rgba(0, 0, 0, 0.5); background-clip: padding-box; } + +.osd spinbutton.vertical > text:disabled, .osd spinbutton:disabled:not(.vertical), .osd entry:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: rgba(58, 58, 57, 0.5); background-clip: padding-box; } + +spinbutton.vertical > text > progress, spinbutton:not(.vertical) > progress, entry > progress { margin-bottom: 2px; } + +spinbutton.vertical > text progress > trough > progress, spinbutton:not(.vertical) progress > trough > progress, entry progress > trough > progress { background-color: transparent; background-image: none; border-radius: 0; border-width: 0 0 2px; border-color: #15539e; border-style: solid; box-shadow: none; } + +spinbutton.vertical.linked:not(.vertical) > text:drop(active) + text, spinbutton.vertical.linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + text, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + spinbutton:not(.vertical), .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + spinbutton:not(.vertical), spinbutton.vertical.linked:not(.vertical) > text:drop(active) + button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + menubutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + menubutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + dropdown > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + dropdown > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + colorbutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + colorbutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + fontbutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + fontbutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + filechooserbutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + filechooserbutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + combobox > box > button.combo, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + combobox > box > button.combo, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + entry, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + entry, .linked:not(.vertical) > entry:drop(active) + button, .linked:not(.vertical) > entry:drop(active) + menubutton > button, .linked:not(.vertical) > entry:drop(active) + dropdown > button, .linked:not(.vertical) > entry:drop(active) + colorbutton > button, .linked:not(.vertical) > entry:drop(active) + fontbutton > button, .linked:not(.vertical) > entry:drop(active) + filechooserbutton > button, .linked:not(.vertical) > entry:drop(active) + combobox > box > button.combo, spinbutton.vertical.linked:not(.vertical) > entry:drop(active) + text, .linked:not(.vertical) > entry:drop(active) + spinbutton:not(.vertical), .linked:not(.vertical) > entry:drop(active) + entry { border-left-color: #26a269; } + +spinbutton.vertical.linked > text:not(:disabled) + entry:not(:disabled), .linked.vertical > spinbutton:not(:disabled):not(.vertical) + entry:not(:disabled), spinbutton.vertical.linked > text:not(:disabled) + text:not(:disabled), spinbutton.vertical.linked > spinbutton:not(:disabled):not(.vertical) + text:not(:disabled), spinbutton.vertical.linked > text:not(:disabled) + spinbutton:not(:disabled):not(.vertical), .linked.vertical > spinbutton:not(:disabled):not(.vertical) + spinbutton:not(:disabled):not(.vertical), .linked.vertical > entry:not(:disabled) + entry:not(:disabled), spinbutton.vertical.linked > entry:not(:disabled) + text:not(:disabled), .linked.vertical > entry:not(:disabled) + spinbutton:not(:disabled):not(.vertical) { border-top-color: #282828; } + +spinbutton.vertical.linked > text:disabled + text:disabled, spinbutton.vertical.linked > spinbutton:disabled:not(.vertical) + text:disabled, spinbutton.vertical.linked > text:disabled + spinbutton:disabled:not(.vertical), .linked.vertical > spinbutton:disabled:not(.vertical) + spinbutton:disabled:not(.vertical), spinbutton.vertical.linked > text:disabled + entry:disabled, .linked.vertical > spinbutton:disabled:not(.vertical) + entry:disabled, spinbutton.vertical.linked > entry:disabled + text:disabled, .linked.vertical > entry:disabled + spinbutton:disabled:not(.vertical), .linked.vertical > entry:disabled + entry:disabled { border-top-color: #282828; } + +spinbutton.vertical.linked > text + text:drop(active):not(:only-child), spinbutton.vertical.linked > spinbutton:not(.vertical) + text:drop(active):not(:only-child), spinbutton.vertical.linked > text + spinbutton:drop(active):not(:only-child):not(.vertical), .linked.vertical > spinbutton:not(.vertical) + spinbutton:drop(active):not(:only-child):not(.vertical), spinbutton.vertical.linked > text + entry:drop(active):not(:only-child), .linked.vertical > spinbutton:not(.vertical) + entry:drop(active):not(:only-child), spinbutton.vertical.linked > entry + text:drop(active):not(:only-child), .linked.vertical > entry + spinbutton:drop(active):not(:only-child):not(.vertical), .linked.vertical > entry + entry:drop(active):not(:only-child) { border-top-color: #26a269; } + +spinbutton.vertical.linked > text:drop(active):not(:only-child) + text, spinbutton.vertical.linked > spinbutton:drop(active):not(:only-child):not(.vertical) + text, spinbutton.vertical.linked > text:drop(active):not(:only-child) + spinbutton:not(.vertical), .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + spinbutton:not(.vertical), spinbutton.vertical.linked > text:drop(active):not(:only-child) + entry, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + entry, spinbutton.vertical.linked > text:drop(active):not(:only-child) + button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + menubutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + menubutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + dropdown > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + dropdown > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + colorbutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + colorbutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + fontbutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + fontbutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + filechooserbutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + filechooserbutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + combobox > box > button.combo, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + combobox > box > button.combo, spinbutton.vertical.linked > entry:drop(active):not(:only-child) + text, .linked.vertical > entry:drop(active):not(:only-child) + spinbutton:not(.vertical), .linked.vertical > entry:drop(active):not(:only-child) + entry, .linked.vertical > entry:drop(active):not(:only-child) + button, .linked.vertical > entry:drop(active):not(:only-child) + menubutton > button, .linked.vertical > entry:drop(active):not(:only-child) + dropdown > button, .linked.vertical > entry:drop(active):not(:only-child) + colorbutton > button, .linked.vertical > entry:drop(active):not(:only-child) + fontbutton > button, .linked.vertical > entry:drop(active):not(:only-child) + filechooserbutton > button, .linked.vertical > entry:drop(active):not(:only-child) + combobox > box > button.combo { border-top-color: #26a269; } + +spinbutton.vertical > text.error, spinbutton.error:not(.vertical), entry.error { color: #cc0000; } + +treeview entry:focus-within:dir(rtl), treeview entry:focus-within:dir(ltr) { background-color: #2d2d2d; transition-property: color, background; } + +treeview entry.flat, treeview entry { border-radius: 0; background-image: none; background-color: #2d2d2d; } + +treeview entry.flat:focus-within, treeview entry:focus-within { border-color: #15539e; } + +/******************* Editable Labels * */ +editablelabel > stack > text { color: white; border-color: #1b1b1b; background-color: #2d2d2d; } + +/*********** Buttons * */ +@keyframes needs_attention { from { background-image: radial-gradient(farthest-side, #1f76e1 0%, rgba(31, 118, 225, 0) 0%); } + to { background-image: radial-gradient(farthest-side, #1f76e1 95%, rgba(31, 118, 225, 0)); } } + +notebook > header > tabs > arrow, windowcontrols button, button { min-height: 24px; min-width: 16px; padding: 4px 9px; border: 1px solid; border-radius: 5px; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); color: #eeeeec; outline-color: rgba(21, 83, 158, 0.7); border-color: #1b1b1b; background-image: linear-gradient(to top, #373737 2px, #3a3a3a); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +notebook > header > tabs > arrow, windowcontrols button, button { outline: 0 solid transparent; outline-offset: 4px; } + +notebook > header > tabs > arrow:focus:focus-visible, button:focus:focus-visible { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: -2px; } + +notebook > header > tabs > arrow:hover, button:hover { color: #eeeeec; border-color: #1b1b1b; background-image: linear-gradient(to top, #303030 20%, #323232 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); -gtk-icon-filter: brightness(1.2); } + +notebook > header > tabs > arrow.keyboard-activating, notebook > header > tabs > arrow:active, notebook > header > tabs > arrow:checked, button.keyboard-activating, button:active, button:checked { color: #eeeeec; border-color: #1b1b1b; background-image: image(#232323); box-shadow: none; transition-duration: 50ms; } + +notebook > header > tabs > arrow:checked:hover, button:checked:hover { color: #eeeeec; border-color: #1b1b1b; background-image: image(#1b1b1b); box-shadow: none; } + +notebook > header > tabs > arrow:checked:active, button:checked:active { color: #eeeeec; border-color: #1b1b1b; background-image: image(#161616); box-shadow: none; } + +notebook > header > tabs > arrow:backdrop, button.flat:backdrop, button:backdrop { color: #919190; border-color: #202020; background-image: image(#353535); box-shadow: none; transition: 200ms ease-out; } + +notebook > header > tabs > arrow:backdrop:not(:disabled), button.flat:backdrop:not(:disabled), button:backdrop:not(:disabled) { -gtk-icon-filter: none; } + +notebook > header > tabs > arrow:backdrop:active, notebook > header > tabs > arrow:backdrop:checked, button.flat:backdrop:active, button.flat:backdrop:checked, button:backdrop:active, button:backdrop:checked { color: #919190; border-color: #202020; background-image: image(#2e2e2e); box-shadow: none; } + +notebook > header > tabs > arrow:backdrop:disabled, button.flat:backdrop:disabled, button:backdrop:disabled { color: #5b5b5b; border-color: #202020; background-image: image(#323232); box-shadow: none; } + +notebook > header > tabs > arrow:backdrop:disabled:active, notebook > header > tabs > arrow:backdrop:disabled:checked, button.flat:backdrop:disabled:active, button.flat:backdrop:disabled:checked, button:backdrop:disabled:active, button:backdrop:disabled:checked { color: #5b5b5b; border-color: #202020; background-image: image(#2e2e2e); box-shadow: none; } + +notebook > header > tabs > arrow:disabled, button:disabled { color: #919190; border-color: #202020; background-image: image(#323232); -gtk-icon-filter: opacity(0.5); } + +notebook > header > tabs > arrow:disabled:active, notebook > header > tabs > arrow:disabled:checked, button:disabled:active, button:disabled:checked { color: #919190; border-color: #202020; background-image: image(#292929); box-shadow: none; } + - button.sidebar-button, notebook > header > tabs > arrow, windowcontrols button, notebook > header > tabs > arrow.flat, button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; transition: none; } ++button.sidebar-button, notebook > header > tabs > arrow, windowcontrols button, .toolbar button, notebook > header > tabs > arrow.flat, button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; transition: none; } + - button.sidebar-button:hover, notebook > header > tabs > arrow:hover, windowcontrols button:hover, button.flat:hover { border-color: transparent; background-image: none; box-shadow: none; background-color: #373737; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-duration: 500ms; } ++button.sidebar-button:hover, notebook > header > tabs > arrow:hover, windowcontrols button:hover, .toolbar button:hover, button.flat:hover { border-color: transparent; background-image: none; box-shadow: none; background-color: #373737; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-duration: 500ms; } + - button.keyboard-activating.sidebar-button, notebook > header > tabs > arrow.keyboard-activating, windowcontrols button.keyboard-activating, button.sidebar-button:active, notebook > header > tabs > arrow:active, windowcontrols button:active, button.sidebar-button:checked, notebook > header > tabs > arrow:checked, windowcontrols button:checked, button.flat.keyboard-activating, button.flat:active, button.flat:checked { border-color: transparent; background-image: none; box-shadow: none; background-color: #2d2d2d; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } ++button.keyboard-activating.sidebar-button, notebook > header > tabs > arrow.keyboard-activating, windowcontrols button.keyboard-activating, .toolbar button.keyboard-activating, button.sidebar-button:active, notebook > header > tabs > arrow:active, windowcontrols button:active, .toolbar button:active, button.sidebar-button:checked, notebook > header > tabs > arrow:checked, windowcontrols button:checked, .toolbar button:checked, button.flat.keyboard-activating, button.flat:active, button.flat:checked { border-color: transparent; background-image: none; box-shadow: none; background-color: #2d2d2d; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + - button.sidebar-button:backdrop, notebook > header > tabs > arrow:backdrop, windowcontrols button:backdrop, button.sidebar-button:disabled, notebook > header > tabs > arrow:disabled, windowcontrols button:disabled, button.flat:backdrop, button.flat:disabled, button.flat:backdrop:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; } ++button.sidebar-button:backdrop, notebook > header > tabs > arrow:backdrop, windowcontrols button:backdrop, .toolbar button:backdrop, button.sidebar-button:disabled, notebook > header > tabs > arrow:disabled, windowcontrols button:disabled, .toolbar button:disabled, button.flat:backdrop, button.flat:disabled, button.flat:backdrop:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; } + +notebook > header > tabs > arrow.image-button, button.image-button { min-width: 24px; padding-left: 5px; padding-right: 5px; } + +notebook > header > tabs > arrow.text-button, button.text-button { padding-left: 16px; padding-right: 16px; } + +notebook > header > tabs > arrow.text-button.image-button, button.text-button.image-button { padding-left: 8px; padding-right: 8px; } + +notebook > header > tabs > arrow.text-button.image-button label, button.text-button.image-button label { padding-left: 8px; padding-right: 8px; } + +dropdown:drop(active) button.combo, combobox:drop(active) button.combo, notebook > header > tabs > arrow:drop(active), button:drop(active) { color: #26a269; border-color: #26a269; box-shadow: inset 0 0 0 1px #26a269; } + +row:selected button.sidebar-button:not(:active):not(:checked):not(:hover):not(disabled), row:selected button.flat:not(:active):not(:checked):not(:hover):not(disabled) { color: #ffffff; border-color: transparent; } + +row:selected button.sidebar-button:not(:active):not(:checked):not(:hover):not(disabled):backdrop, row:selected button.flat:not(:active):not(:checked):not(:hover):not(disabled):backdrop { color: #919190; } + +button.osd { min-width: 26px; min-height: 32px; color: #eeeeec; border-radius: 5px; color: #eeeeec; outline-color: rgba(21, 83, 158, 0.7); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; border: none; box-shadow: none; } + +button.osd.image-button { min-width: 30px; } + +button.osd.image-button:only-child { margin: 4px; border-radius: 50%; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); } + +button.osd:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(12, 12, 12, 0.7)); background-clip: padding-box; border: none; box-shadow: none; } + +button.osd:active, button.osd:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; border: none; box-shadow: none; } + +.app-notification button, popover.background.touch-selection button, popover.background.magnifier button, .osd button { color: #eeeeec; outline-color: rgba(21, 83, 158, 0.7); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; } + +.app-notification button:hover, popover.background.touch-selection button:hover, popover.background.magnifier button:hover, .osd button:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(12, 12, 12, 0.7)); background-clip: padding-box; } + +.app-notification button:active, popover.background.touch-selection button:active, popover.background.magnifier button:active, .app-notification button:checked, popover.background.touch-selection button:checked, popover.background.magnifier button:checked, .osd button:active:backdrop, .osd button:active, .osd button:checked:backdrop, .osd button:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; } + +.app-notification button:disabled, popover.background.touch-selection button:disabled, popover.background.magnifier button:disabled, .osd button:disabled:backdrop, .osd button:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; } + +.app-notification button.flat, popover.background.touch-selection button.flat, popover.background.magnifier button.flat, .osd button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; box-shadow: none; -gtk-icon-shadow: 0 1px black; } + +.app-notification button.flat:hover, popover.background.touch-selection button.flat:hover, popover.background.magnifier button.flat:hover, .osd button.flat:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(12, 12, 12, 0.7)); background-clip: padding-box; } + +.app-notification button.flat:disabled, popover.background.touch-selection button.flat:disabled, popover.background.magnifier button.flat:disabled, .osd button.flat:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; background-image: none; border-color: transparent; box-shadow: none; } + +.app-notification button.flat:active, popover.background.touch-selection button.flat:active, popover.background.magnifier button.flat:active, .app-notification button.flat:checked, popover.background.touch-selection button.flat:checked, popover.background.magnifier button.flat:checked, .osd button.flat:active, .osd button.flat:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; } + +button.suggested-action { color: white; outline-color: rgba(255, 255, 255, 0.3); border-color: #092444; background-image: linear-gradient(to top, #155099 2px, #15539e); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +button.suggested-action { outline: 0 solid transparent; outline-offset: 4px; } + +button.suggested-action:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.3); outline-width: 2px; outline-offset: -2px; } + +button.suggested-action.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #15539e; } + +button.suggested-action:hover { color: white; border-color: #0c2f5a; background-image: linear-gradient(to top, #13498c 20%, #134c90 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +button.suggested-action:active, button.suggested-action:checked { color: white; border-color: #0c2f5a; background-image: image(#103e75); box-shadow: none; } + +button.suggested-action.flat:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: rgba(21, 83, 158, 0.8); } + +button.suggested-action:disabled { color: #919190; border-color: #202020; background-image: image(#323232); } + +button.suggested-action:disabled:active, button.suggested-action:disabled:checked { color: #a1b2c7; border-color: #0c2f5a; background-image: image(#143f73); box-shadow: none; } + +.osd button.suggested-action { color: #eeeeec; outline-color: rgba(255, 255, 255, 0.3); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(21, 83, 158, 0.5)); background-clip: padding-box; } + +.osd button.suggested-action:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(21, 83, 158, 0.7)); background-clip: padding-box; } + +.osd button.suggested-action:active:backdrop, .osd button.suggested-action:active, .osd button.suggested-action:checked:backdrop, .osd button.suggested-action:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(#15539e); background-clip: padding-box; box-shadow: none; } + +.osd button.suggested-action:disabled:backdrop, .osd button.suggested-action:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; } + +button.destructive-action { color: white; outline-color: rgba(255, 255, 255, 0.3); border-color: #570b0e; background-image: linear-gradient(to top, #ae151c 2px, #b2161d); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +button.destructive-action { outline: 0 solid transparent; outline-offset: 4px; } + +button.destructive-action:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.3); outline-width: 2px; outline-offset: -2px; } + +button.destructive-action.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #b2161d; } + +button.destructive-action:hover { color: white; border-color: #6e0d12; background-image: linear-gradient(to top, #a0131a 20%, #a5141a 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +button.destructive-action:active, button.destructive-action:checked { color: white; border-color: #6e0d12; background-image: image(#8a1116); box-shadow: none; } + +button.destructive-action.flat:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: rgba(178, 22, 29, 0.8); } + +button.destructive-action:disabled { color: #919190; border-color: #202020; background-image: image(#323232); } + +button.destructive-action:disabled:active, button.destructive-action:disabled:checked { color: #cea1a3; border-color: #6e0d12; background-image: image(#84151a); box-shadow: none; } + +.osd button.destructive-action { color: #eeeeec; outline-color: rgba(255, 255, 255, 0.3); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(178, 22, 29, 0.5)); background-clip: padding-box; } + +.osd button.destructive-action:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(178, 22, 29, 0.7)); background-clip: padding-box; } + +.osd button.destructive-action:active:backdrop, .osd button.destructive-action:active, .osd button.destructive-action:checked:backdrop, .osd button.destructive-action:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(#b2161d); background-clip: padding-box; box-shadow: none; } + +.osd button.destructive-action:disabled:backdrop, .osd button.destructive-action:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; } + +stackswitcher > button > label { padding: 0 6px; margin: 0 -6px; } + +stackswitcher > button > image { padding: 3px 6px; margin: -3px -6px; } + +button.font separator { background-color: transparent; } + +button.font > box { border-spacing: 6px; } + +button.font > box > box > label { font-weight: bold; } + +menubutton.circular button, button.circular { min-width: 32px; min-height: 32px; padding: 0; border-radius: 9999px; } + +menubutton.circular button label, button.circular label { padding: 0; } + +stacksidebar row.needs-attention > label, stackswitcher > button.needs-attention > label, stackswitcher > button.needs-attention > image { animation: needs_attention 150ms ease-in; background-image: radial-gradient(farthest-side, #1f76e1 96%, rgba(31, 118, 225, 0)); background-size: 6px 6px, 6px 6px; background-repeat: no-repeat; background-position: right 3px, right 2px; } + +stacksidebar row.needs-attention > label:backdrop, stackswitcher > button.needs-attention > label:backdrop, stackswitcher > button.needs-attention > image:backdrop { background-size: 6px 6px, 0 0; } + +stacksidebar row.needs-attention > label:dir(rtl), stackswitcher > button.needs-attention > label:dir(rtl), stackswitcher > button.needs-attention > image:dir(rtl) { background-position: left 3px, left 2px; } + +.linked:not(.vertical) > filechooserbutton > combobox:dir(rtl):not(:last-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(rtl):not(:last-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(rtl):not(:last-child) > box > button.combo, .linked:not(.vertical) > filechooserbutton > combobox:dir(ltr):not(:first-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(ltr):not(:first-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(ltr):not(:first-child) > box > button.combo, dropdown.linked button:nth-child(2):dir(ltr), combobox.linked button:nth-child(2):dir(ltr), .linked:not(.vertical) > menubutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > dropdown:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > colorbutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > fontbutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > filechooserbutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > menubutton:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > dropdown:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > colorbutton:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > fontbutton:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > filechooserbutton:dir(ltr):not(:first-child) > button, spinbutton.vertical.linked:not(.vertical) > text:dir(rtl):not(:last-child), .linked:not(.vertical) > spinbutton:dir(rtl):not(:last-child):not(.vertical), .linked:not(.vertical) > entry:dir(rtl):not(:last-child), .linked:not(.vertical) > button:dir(rtl):not(:last-child), spinbutton.vertical.linked:not(.vertical) > text:dir(ltr):not(:first-child), .linked:not(.vertical) > spinbutton:dir(ltr):not(:first-child):not(.vertical), .linked:not(.vertical) > entry:dir(ltr):not(:first-child), .linked:not(.vertical) > button:dir(ltr):not(:first-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; } + +.linked:not(.vertical) > filechooserbutton > combobox:dir(rtl):not(:first-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(rtl):not(:first-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(rtl):not(:first-child) > box > button.combo, .linked:not(.vertical) > filechooserbutton > combobox:dir(ltr):not(:last-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(ltr):not(:last-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(ltr):not(:last-child) > box > button.combo, dropdown.linked button:nth-child(2):dir(rtl), combobox.linked button:nth-child(2):dir(rtl), .linked:not(.vertical) > menubutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > dropdown:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > colorbutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > fontbutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > filechooserbutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > menubutton:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > dropdown:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > colorbutton:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > fontbutton:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > filechooserbutton:dir(ltr):not(:last-child) > button, spinbutton.vertical.linked:not(.vertical) > text:dir(rtl):not(:first-child), .linked:not(.vertical) > spinbutton:dir(rtl):not(:first-child):not(.vertical), .linked:not(.vertical) > entry:dir(rtl):not(:first-child), .linked:not(.vertical) > button:dir(rtl):not(:first-child), spinbutton.vertical.linked:not(.vertical) > text:dir(ltr):not(:last-child), .linked:not(.vertical) > spinbutton:dir(ltr):not(:last-child):not(.vertical), .linked:not(.vertical) > entry:dir(ltr):not(:last-child), .linked:not(.vertical) > button:dir(ltr):not(:last-child) { border-right-style: none; border-top-right-radius: 0; border-bottom-right-radius: 0; } + +.linked.vertical > filechooserbutton > combobox:not(:first-child) > box > button.combo, .linked.vertical > appchooserbutton > combobox:not(:first-child) > box > button.combo, .linked.vertical > combobox:not(:first-child) > box > button.combo, .linked.vertical > menubutton:not(:first-child) > button, .linked.vertical > dropdown:not(:first-child) > button, .linked.vertical > colorbutton:not(:first-child) > button, .linked.vertical > fontbutton:not(:first-child) > button, .linked.vertical > filechooserbutton:not(:first-child) > button, spinbutton.vertical.linked > text:not(:first-child), .linked.vertical > spinbutton:not(:first-child):not(.vertical), .linked.vertical > entry:not(:first-child), .linked.vertical > button:not(:first-child) { border-top-left-radius: 0; border-top-right-radius: 0; } + +.linked.vertical > filechooserbutton > combobox:not(:last-child) > box > button.combo, .linked.vertical > appchooserbutton > combobox:not(:last-child) > box > button.combo, .linked.vertical > combobox:not(:last-child) > box > button.combo, .linked.vertical > menubutton:not(:last-child) > button, .linked.vertical > dropdown:not(:last-child) > button, .linked.vertical > colorbutton:not(:last-child) > button, .linked.vertical > fontbutton:not(:last-child) > button, .linked.vertical > filechooserbutton:not(:last-child) > button, spinbutton.vertical.linked > text:not(:last-child), .linked.vertical > spinbutton:not(:last-child):not(.vertical), .linked.vertical > entry:not(:last-child), .linked.vertical > button:not(:last-child) { border-bottom-style: none; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } + - .scale-popup button:hover, button.link, button.link:hover, button.link:active, button.link:checked, popover.menu box.circular-buttons button.circular.image-button.model, list > row button.image-button:not(.flat), .toolbar button, modelbutton.flat { background-color: transparent; background-image: none; border-color: transparent; box-shadow: inset 0 1px rgba(255, 255, 255, 0), 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; } ++.scale-popup button:hover, button.link, button.link:hover, button.link:active, button.link:checked, popover.menu box.circular-buttons button.circular.image-button.model, list > row button.image-button:not(.flat), modelbutton.flat { background-color: transparent; background-image: none; border-color: transparent; box-shadow: inset 0 1px rgba(255, 255, 255, 0), 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; } + +/* menu buttons */ +modelbutton.flat { min-height: 26px; padding-left: 5px; padding-right: 5px; border-radius: 5px; } + +modelbutton.flat:hover { background-color: #202020; } + +modelbutton.flat:disabled { color: #919190; } + +modelbutton.flat arrow { background: none; min-width: 16px; min-height: 16px; opacity: 0.3; } + +modelbutton.flat arrow:hover { background: none; } + +modelbutton.flat arrow.left { -gtk-icon-source: -gtk-icontheme("go-previous-symbolic"); } + +modelbutton.flat arrow.right { -gtk-icon-source: -gtk-icontheme("go-next-symbolic"); } + +/* oldstyle toolbar buttons */ +.toolbar button { margin: 1px; } + - .toolbar button:hover { color: #eeeeec; border-color: #1b1b1b; background-image: linear-gradient(to top, #303030 20%, #323232 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } - - .toolbar button:active { color: #eeeeec; border-color: #1b1b1b; background-image: image(#232323); box-shadow: none; } - - .toolbar button:disabled { color: #919190; border-color: #202020; background-image: image(#323232); } - - .toolbar button:backdrop { color: #919190; border-color: #202020; background-image: image(#353535); box-shadow: none; } - - .toolbar button:backdrop:disabled { color: #5b5b5b; border-color: #202020; background-image: image(#323232); box-shadow: none; } - +button.color { padding: 4px; } + +button.color > colorswatch:only-child, button.color > colorswatch:only-child > overlay { border-radius: 0; } + +/* list buttons */ +/* tone down as per new designs, see issue #1473 */ +popover.menu box.circular-buttons button.circular.image-button.model, list > row button.image-button:not(.flat) { border: 1px solid rgba(27, 27, 27, 0.5); } + +popover.menu box.circular-buttons button.circular.image-button.model:hover, list > row button.image-button:not(.flat):hover { color: #eeeeec; border-color: #1b1b1b; background-image: linear-gradient(to top, #303030 20%, #323232 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +popover.menu box.circular-buttons button.circular.image-button.model:active, popover.menu box.circular-buttons button.circular.image-button.model:checked, list > row button.image-button:not(.flat):active, list > row button.image-button:not(.flat):checked { color: #eeeeec; border-color: #1b1b1b; background-image: image(#232323); box-shadow: none; } + +popover.menu box.circular-buttons button.suggested-action.circular.image-button.model, list > row button.image-button.suggested-action:not(.flat) { color: white; outline-color: rgba(255, 255, 255, 0.3); border-color: #092444; background-image: linear-gradient(to top, #155099 2px, #15539e); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +popover.menu box.circular-buttons button.suggested-action.circular.image-button.model, list > row button.image-button.suggested-action:not(.flat) { outline: 0 solid transparent; outline-offset: 4px; } + +popover.menu box.circular-buttons button.suggested-action.circular.image-button.model:focus:focus-visible, list > row button.image-button.suggested-action:not(.flat):focus:focus-visible { outline-color: rgba(255, 255, 255, 0.3); outline-width: 2px; outline-offset: -2px; } + +popover.menu box.circular-buttons button.destructive-action.circular.image-button.model, list > row button.image-button.destructive-action:not(.flat) { color: white; outline-color: rgba(255, 255, 255, 0.3); border-color: #570b0e; background-image: linear-gradient(to top, #ae151c 2px, #b2161d); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +popover.menu box.circular-buttons button.destructive-action.circular.image-button.model, list > row button.image-button.destructive-action:not(.flat) { outline: 0 solid transparent; outline-offset: 4px; } + +popover.menu box.circular-buttons button.destructive-action.circular.image-button.model:focus:focus-visible, list > row button.image-button.destructive-action:not(.flat):focus:focus-visible { outline-color: rgba(255, 255, 255, 0.3); outline-width: 2px; outline-offset: -2px; } + +/********* Links * */ +button.link, link { color: #3584e4; text-decoration: underline; } + +button.link:visited, link:visited { color: #1b6acb; } + +*:selected button.link:visited, *:selected link:visited { color: #a4c4ea; } + +button.link:hover, link:hover { color: #629fea; } + +*:selected button.link:hover, *:selected link:hover { color: #eff5fd; } + +button.link:active, link:active { color: #3584e4; } + +*:selected button.link:active, *:selected link:active { color: #d7e6fa; } + +button.link:disabled, link:disabled { color: rgba(141, 141, 141, 0.8); } + +button.link:selected, *:selected button.link, link:selected, *:selected link { color: #d7e6fa; } + +link { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +link { outline: 0 solid transparent; outline-offset: 4px; } + +link:focus:focus-visible { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: -2px; } + +button.link, button.link:hover, button.link:active, button.link:checked { text-shadow: none; } + +button.link > label { text-decoration: underline; } + +/***************** GtkSpinButton * */ +spinbutton { font-feature-settings: "tnum"; } + +spinbutton:not(.vertical) { padding: 0; border-spacing: 0; /* :not here just to bump specificity above that of the list button styling */ } + +.osd spinbutton:not(.vertical) > text, spinbutton:not(.vertical) > text { min-width: 28px; margin: 0; background: none; background-color: transparent; border: none; border-radius: 0; box-shadow: none; padding: 6px; } + +.osd spinbutton:not(.vertical) > text:backdrop:disabled, spinbutton:not(.vertical) > text:backdrop:disabled { background-color: transparent; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat), spinbutton:not(.vertical) > button.image-button.down:not(.flat) { min-height: 16px; margin: 0; padding-bottom: 0; padding-top: 0; color: #dbdbd9; background-image: none; border-style: none none none solid; border-color: rgba(27, 27, 27, 0.3); border-radius: 0; box-shadow: none; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl), spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl) { border-style: none solid none none; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):hover, spinbutton:not(.vertical) > button.image-button.down:not(.flat):hover { color: #eeeeec; background-color: #282828; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):disabled, spinbutton:not(.vertical) > button.image-button.down:not(.flat):disabled { color: rgba(145, 145, 144, 0.3); background-color: transparent; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):active, spinbutton:not(.vertical) > button.image-button.down:not(.flat):active { background-color: rgba(0, 0, 0, 0.1); box-shadow: inset 0 2px 3px -1px rgba(0, 0, 0, 0.2); } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(ltr):last-child, spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(ltr):last-child { border-radius: 0 5px 5px 0; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl):first-child, spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl):first-child { border-radius: 5px 0 0 5px; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat), .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat) { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #eeeeec; border-style: none none none solid; border-color: rgba(0, 0, 0, 0.4); border-radius: 0; box-shadow: none; -gtk-icon-shadow: 0 1px black; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl), .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl) { border-style: none solid none none; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):hover, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):hover { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #eeeeec; border-color: rgba(0, 0, 0, 0.5); background-color: rgba(12, 12, 12, 0.7); -gtk-icon-shadow: 0 1px black; box-shadow: none; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):disabled, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #8a8a89; border-color: rgba(0, 0, 0, 0.5); -gtk-icon-shadow: none; box-shadow: none; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(ltr):last-child, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(ltr):last-child { border-radius: 0 5px 5px 0; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl):first-child, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl):first-child { border-radius: 5px 0 0 5px; } + +spinbutton.vertical:disabled { color: #919190; } + +spinbutton.vertical:drop(active) { border-color: transparent; box-shadow: none; } + +spinbutton.vertical > text { min-height: 32px; min-width: 32px; padding: 0; border-radius: 0; } + +spinbutton.vertical > text > block-cursor { color: #2d2d2d; background-color: white; } + +spinbutton.vertical > button { min-height: 32px; min-width: 32px; padding: 0; } + +spinbutton.vertical > button.up { border-bottom-style: none; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } + +spinbutton.vertical > button.down { border-top-style: none; border-top-left-radius: 0; border-top-right-radius: 0; } + +.osd spinbutton.vertical > button:first-child { color: #eeeeec; outline-color: rgba(21, 83, 158, 0.7); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; } + +.osd spinbutton.vertical > button:first-child:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(12, 12, 12, 0.7)); background-clip: padding-box; } + +.osd spinbutton.vertical > button:first-child:active { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; } + +.osd spinbutton.vertical > button:first-child:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; } + +treeview spinbutton:not(.vertical) { min-height: 0; border-style: none; border-radius: 0; } + +treeview spinbutton:not(.vertical) > text { min-height: 0; padding: 1px 2px; } + +/************** ComboBoxes * */ +dropdown > popover.menu.background > contents { padding: 0; } + +dropdown > button > box { border-spacing: 6px; } + +dropdown > button > box > stack > row.activatable:hover { background: none; box-shadow: none; } + +dropdown arrow, combobox arrow { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); min-height: 16px; min-width: 16px; } + +dropdown > popover.menu > contents modelbutton, combobox > popover.menu > contents modelbutton { padding-left: 9px; padding-right: 9px; } + +dropdown:drop(active), combobox:drop(active) { box-shadow: none; } + +dropdown popover, combobox popover { margin-top: 6px; padding: 0; } + +dropdown popover listview, combobox popover listview { margin: 8px 0; } + +dropdown popover listview > row.activatable, combobox popover listview > row.activatable { padding: 8px; } + +dropdown popover listview > row.activatable:selected, dropdown popover listview > row.activatable:selected:hover, combobox popover listview > row.activatable:selected, combobox popover listview > row.activatable:selected:hover { outline-color: rgba(255, 255, 255, 0.3); color: white; background-color: #202020; box-shadow: none; } + +dropdown popover .dropdown-searchbar, combobox popover .dropdown-searchbar { padding: 6px; border-bottom: 1px solid #1b1b1b; } + +/************ Toolbars * */ +searchbar > revealer > box, .toolbar, toolbar { padding: 4px; border-spacing: 4px; background-color: #353535; } + +.osd .toolbar, .osd toolbar { background-color: transparent; } + +.toolbar.osd, toolbar.osd { padding: 13px; border: none; border-radius: 5px; background-color: rgba(38, 38, 38, 0.7); } + +.toolbar.osd.left, .toolbar.osd.right, .toolbar.osd.top, .toolbar.osd.bottom, toolbar.osd.left, toolbar.osd.right, toolbar.osd.top, toolbar.osd.bottom { border-radius: 0; } + +.toolbar.horizontal > separator, toolbar.horizontal > separator { margin: 4px 0; } + +.toolbar.vertical > separator, toolbar.vertical > separator { margin: 0 4px; } + +searchbar > revealer > box { padding: 6px; border-spacing: 6px; border-width: 0 0 1px; } + +searchbar > revealer > box { border-style: solid; border-color: #1b1b1b; background-color: #2d2d2d; } + +searchbar > revealer > box:backdrop { border-color: #202020; background-color: #2e2e2e; box-shadow: none; transition: 200ms ease-out; } + +/************** GtkInfoBar * */ +infobar > revealer > box { padding: 8px; border-spacing: 12px; } + +infobar.action:hover > revealer > box { background-color: #3e3b37; } + +infobar.info > revealer > box, infobar.question > revealer > box, infobar.warning > revealer > box, infobar.error > revealer > box { border-bottom: 1px solid #282828; background-color: #44403b; } + +infobar .close, searchbar .close { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; min-width: 16px; min-height: 16px; padding: 4px; border-radius: 50%; } + +infobar .close:hover, searchbar .close:hover { color: #eeeeec; border-color: #1b1b1b; background-image: linear-gradient(to top, #303030 20%, #323232 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +/***************** Title buttons * */ +windowcontrols { border-spacing: 6px; } + +windowcontrols.start:not(.empty):dir(ltr), windowcontrols.end:not(.empty):dir(rtl) { margin-right: 7px; } + +windowcontrols.start:not(.empty):dir(rtl), windowcontrols.end:not(.empty):dir(ltr) { margin-left: 7px; } + +windowcontrols button { border-radius: 9999px; padding: 6px; margin: 0 2px; min-width: 0; min-height: 0; } + +windowcontrols button:hover { border-color: transparent; background-image: none; box-shadow: none; background-color: #1b1b1b; } + +windowcontrols button:active, windowcontrols button:checked { border-color: transparent; background-image: none; box-shadow: none; background-color: #070707; } + +/*************** Header bars * */ +.titlebar:not(headerbar), headerbar { padding: 0 6px; min-height: 46px; border-width: 0 0 1px; border-style: solid; border-color: #070707; border-radius: 0; background: #1b1b1b linear-gradient(to top, #262626, #2b2b2b); /* Darken switchbuttons for headerbars. issue #1588 */ } + +.titlebar:backdrop:not(headerbar), headerbar:backdrop { border-color: #202020; background-color: #353535; background-image: none; transition: 200ms ease-out; } + +.titlebar:not(headerbar) .title, headerbar .title { padding-left: 12px; padding-right: 12px; font-weight: bold; } + +.titlebar:not(headerbar) .subtitle, headerbar .subtitle { font-size: smaller; padding-left: 12px; padding-right: 12px; } + +.titlebar:not(headerbar) stackswitcher > button:checked, .titlebar:not(headerbar) button.toggle:checked, headerbar stackswitcher > button:checked, headerbar button.toggle:checked { background: image(#1e1e1e); border-color: #141414; border-top-color: #070707; } + +.titlebar:not(headerbar) stackswitcher > button:checked:backdrop, .titlebar:not(headerbar) button.toggle:checked:backdrop, headerbar stackswitcher > button:checked:backdrop, headerbar button.toggle:checked:backdrop { color: #919190; border-color: #202020; background-image: image(#2e2e2e); box-shadow: none; } + +.tiled .titlebar:not(headerbar), .tiled-top .titlebar:not(headerbar), .tiled-left .titlebar:not(headerbar), .tiled-right .titlebar:not(headerbar), .tiled-bottom .titlebar:not(headerbar), .maximized .titlebar:not(headerbar), .fullscreen .titlebar:not(headerbar), .tiled headerbar, .tiled-top headerbar, .tiled-left headerbar, .tiled-right headerbar, .tiled-bottom headerbar, .maximized headerbar, .fullscreen headerbar { border-radius: 0; } + +.default-decoration.titlebar:not(headerbar), headerbar.default-decoration { min-height: 28px; padding: 4px; } + +.default-decoration.titlebar:not(headerbar) windowcontrols button, .default-decoration.titlebar:not(headerbar) windowcontrols menubutton, headerbar.default-decoration windowcontrols button, headerbar.default-decoration windowcontrols menubutton { min-height: 26px; min-width: 26px; margin: 0; padding: 0; } + +.default-decoration.titlebar:not(headerbar) windowcontrols menubutton button, headerbar.default-decoration windowcontrols menubutton button { min-height: 20px; min-width: 20px; margin: 0; padding: 4px; } + +.solid-csd .titlebar:dir(rtl):not(headerbar), .solid-csd .titlebar:dir(ltr):not(headerbar), .solid-csd headerbar:backdrop:dir(rtl), .solid-csd headerbar:backdrop:dir(ltr), .solid-csd headerbar:dir(rtl), .solid-csd headerbar:dir(ltr) { margin-left: -1px; margin-right: -1px; margin-top: -1px; border-radius: 0; box-shadow: none; } + +headerbar > windowhandle > box, headerbar > windowhandle > box > box.start, headerbar > windowhandle > box > box.end { border-spacing: 6px; } + +headerbar entry, headerbar spinbutton, headerbar separator:not(.sidebar), headerbar button, headerbar menubutton { margin-top: 6px; margin-bottom: 6px; } + +headerbar menubutton > button { margin-top: 0px; margin-bottom: 0px; } + +headerbar switch { margin-top: 10px; margin-bottom: 10px; } + +window.csd > .titlebar:not(headerbar) { padding: 0; background-color: transparent; background-image: none; border-style: none; border-color: transparent; } + +.titlebar:not(headerbar) separator { background-color: #1b1b1b; } + +window.devel headerbar.titlebar { background: #353535 cross-fade(10% -gtk-icontheme("system-run-symbolic"), image(transparent)) 90% 0/256px 256px no-repeat, linear-gradient(to right, transparent 65%, rgba(21, 83, 158, 0.1)), linear-gradient(to top, #232323 3px, #282828); } + +window.devel headerbar.titlebar:backdrop { background: #353535 cross-fade(10% -gtk-icontheme("system-run-symbolic"), image(transparent)) 90% 0/256px 256px no-repeat, image(#353535); /* background-color would flash */ } + +/************ Pathbars * */ +pathbar > button.text-button, pathbar > button.image-button, pathbar > button { padding-left: 4px; padding-right: 4px; } + +pathbar > button.text-button.image-button label { padding-left: 0; padding-right: 0; } + +pathbar > button.text-button.image-button label:last-child, pathbar > button label:last-child { padding-right: 8px; } + +pathbar > button.text-button.image-button label:first-child, pathbar > button label:first-child { padding-left: 8px; } + +pathbar > button image { padding-left: 4px; padding-right: 4px; } + +pathbar > button.slider-button { padding-left: 0; padding-right: 0; } + +/************** Tree Views * */ +columnview.view, treeview.view { border-left-color: #545453; border-top-color: #545453; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +columnview.view, treeview.view { outline: 0 solid transparent; outline-offset: 4px; } + +columnview.view:focus:focus-visible, treeview.view:focus:focus-visible { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: -2px; } + +columnview.view:selected:focus, columnview.view:selected, treeview.view:selected:focus, treeview.view:selected { border-radius: 0; outline-color: rgba(255, 255, 255, 0.3); } + +columnview.view:disabled, treeview.view:disabled { color: #919190; } + +columnview.view:disabled:selected, treeview.view:disabled:selected { color: #7398c5; } + +columnview.view:disabled:selected:backdrop, treeview.view:disabled:selected:backdrop { color: #4f7aaf; } + +columnview.view.separator, treeview.view.separator { min-height: 2px; color: #545453; } + +columnview.view:backdrop, treeview.view:backdrop { border-left-color: #414141; border-top: #414141; } + +columnview.view:drop(active), treeview.view:drop(active) { box-shadow: none; } + +columnview.view > dndtarget:drop(active), treeview.view > dndtarget:drop(active) { border-style: solid none; border-width: 1px; border-color: #030c17; } + +columnview.view > dndtarget.after:drop(active), treeview.view > dndtarget.after:drop(active) { border-top-style: none; } + +columnview.view > dndtarget.before:drop(active), treeview.view > dndtarget.before:drop(active) { border-bottom-style: none; } + +columnview.view.expander, treeview.view.expander { min-width: 16px; min-height: 16px; -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); color: silver; } + +columnview.view.expander:dir(rtl), treeview.view.expander:dir(rtl) { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl"); } + +columnview.view.expander:hover, treeview.view.expander:hover { color: white; } + +columnview.view.expander:selected, treeview.view.expander:selected { color: #b9cbe2; } + +columnview.view.expander:selected:hover, treeview.view.expander:selected:hover { color: #ffffff; } + +columnview.view.expander:checked, treeview.view.expander:checked { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +columnview.view.progressbar, treeview.view.progressbar { background-color: #15539e; background-image: image(#15539e); box-shadow: none; } + +columnview.view.progressbar:selected:focus, columnview.view.progressbar:selected, treeview.view.progressbar:selected:focus, treeview.view.progressbar:selected { box-shadow: inset 0 1px rgba(255, 255, 255, 0.05); background-image: image(#2d2d2d); } + +columnview.view.progressbar:selected:focus:backdrop, columnview.view.progressbar:selected:backdrop, treeview.view.progressbar:selected:focus:backdrop, treeview.view.progressbar:selected:backdrop { background-color: #303030; } + +columnview.view.trough, treeview.view.trough { background-color: rgba(238, 238, 236, 0.1); } + +columnview.view.trough:selected:focus, columnview.view.trough:selected, treeview.view.trough:selected:focus, treeview.view.trough:selected { background-color: #0f3b71; } + +columnview.view > header > button, treeview.view > header > button { color: #8e8e8d; background-color: #2d2d2d; font-weight: bold; text-shadow: none; box-shadow: none; } + +columnview.view > header > button:hover, treeview.view > header > button:hover { color: #bebebd; box-shadow: none; transition: none; } + +columnview.view > header > button:active, treeview.view > header > button:active { color: #eeeeec; transition: none; } + +columnview.view > header > button sort-indicator, treeview.view > header > button sort-indicator { min-height: 16px; min-width: 16px; } + +columnview.view > header > button sort-indicator.ascending, treeview.view > header > button sort-indicator.ascending { -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); } + +columnview.view > header > button sort-indicator.descending, treeview.view > header > button sort-indicator.descending { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +columnview.view button.dnd:active, columnview.view button.dnd:selected, columnview.view button.dnd:hover, columnview.view button.dnd, columnview.view header.button.dnd:active, columnview.view header.button.dnd:selected, columnview.view header.button.dnd:hover, columnview.view header.button.dnd, treeview.view button.dnd:active, treeview.view button.dnd:selected, treeview.view button.dnd:hover, treeview.view button.dnd, treeview.view header.button.dnd:active, treeview.view header.button.dnd:selected, treeview.view header.button.dnd:hover, treeview.view header.button.dnd { padding: 0 6px; color: #2d2d2d; background-image: none; background-color: #15539e; border-style: none; border-radius: 0; box-shadow: inset 0 0 0 1px #2d2d2d; text-shadow: none; transition: none; } + +columnview.view acceleditor > label, treeview.view acceleditor > label { background-color: #15539e; } + +columnview.view > header > button, treeview.view > header > button, columnview.view > header > button:hover, treeview.view > header > button:hover, columnview.view > header > button:active, treeview.view > header > button:active { padding: 0 6px; background-image: none; border-style: none none solid solid; border-color: #545453; border-radius: 0; text-shadow: none; } + +columnview.view > header > button:disabled, treeview.view > header > button:disabled { border-color: #353535; background-image: none; } + +columnview.view > header > button:last-child, treeview.view > header > button:last-child { border-right-style: none; } + +/*************** Popovers * */ +popover.background { background-color: transparent; font: initial; } + +popover.background > arrow, popover.background > contents { background-color: #2d2d2d; background-clip: padding-box; border: 1px solid rgba(0, 0, 0, 0.75); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); } + +popover.background:backdrop { background-color: transparent; } + +popover.background > contents { padding: 8px; border-radius: 9px; } + +popover.background > contents > list, popover.background > contents > .view, popover.background > contents > iconview, popover.background > contents > toolbar { border-style: none; background-color: transparent; } + +popover.background > contents separator { background-color: #232323; margin: 3px; } + +popover.background > contents list separator { margin: 0; } + +.osd popover.background, popover.background.touch-selection, popover.background.magnifier { background-color: transparent; } + +.osd popover.background > arrow, .osd popover.background > contents, popover.background.touch-selection > arrow, popover.background.touch-selection > contents, popover.background.magnifier > arrow, popover.background.magnifier > contents { border: 1px solid rgba(255, 255, 255, 0.1); box-shadow: none; } + +magnifier { background-color: #2d2d2d; } + +/********************** Popover Base Menus * */ +popover.menu { padding: 0; } + +popover.menu box.inline-buttons { padding: 0 12px; } + +popover.menu box.inline-buttons button.image-button.model { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; min-height: 30px; min-width: 30px; padding: 0; border: none; outline: none; transition: none; } + +popover.menu box.inline-buttons button.image-button.model:selected { background: image(#202020); } + +popover.menu box.circular-buttons { padding: 12px 12px 6px; } + +popover.menu box.circular-buttons button.circular.image-button.model { padding: 11px; } + +popover.menu box.circular-buttons button.circular.image-button.model:focus { background-color: #202020; border-color: #202020; } + +popover.menu > arrow, popover.menu.background > contents { background-color: #2d2d2d; padding: 5px; } + +popover.menu.background separator { margin: 6px 0; } + +popover.menu accelerator { color: alpha(currentColor,0.55); } + +popover.menu accelerator:dir(ltr) { margin-left: 12px; } + +popover.menu accelerator:dir(rtl) { margin-right: 12px; } + +popover.menu check, popover.menu radio { transform: scale(0.8); border-width: 1.2px; border-color: transparent; box-shadow: none; background-image: image(transparent); color: white; } + +popover.menu check:hover, popover.menu radio:hover { transform: scale(0.8); border-width: 1.2px; color: white; box-shadow: none; background-image: image(transparent); } + +popover.menu check:active, popover.menu radio:active { transform: scale(0.8); border-width: 1.2px; color: white; box-shadow: none; background-image: image(transparent); } + +popover.menu radio { border-color: #1b1b1b; } + +popover.menu radio:active { border-color: rgba(27, 27, 27, 0.5); } + +popover.menu arrow.left, popover.menu radio.left, popover.menu check.left { margin-left: -2px; margin-right: 6px; } + +popover.menu arrow.right, popover.menu radio.right, popover.menu check.right { margin-left: 6px; margin-right: -2px; } + +popover.menu modelbutton { min-height: 30px; min-width: 40px; padding: 0 12px; border-radius: 5px; } + +popover.menu modelbutton:selected { color: white; background-color: #202020; } + +popover.menu modelbutton:selected:active { background-color: #111111; } + +popover.menu label.title { font-weight: bold; padding: 4px 32px; } + +menubar { padding: 0px; box-shadow: inset 0 -1px rgba(0, 0, 0, 0.1); } + +menubar > item { min-height: 16px; padding: 4px 8px; } + +menubar > item:selected { box-shadow: inset 0 -3px #15539e; color: #3584e4; } + +menubar > item:disabled { color: #919190; box-shadow: none; } + +menubar > item popover.menu.background > contents { padding: 5px; } + +menubar > item popover.menu popover.menu { padding: 0 0 4px 0; } + +menubar > item popover.menu.background popover.menu.background > contents { margin: 0; border-radius: 9px; } + +/************* Notebooks * */ +notebook { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +notebook > header > tabs > tab:checked { outline: 0 solid transparent; outline-offset: 4px; } + +notebook:focus:focus-visible > header > tabs > tab:checked { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: -2px; } + +notebook > header { padding: 1px; border-color: #1b1b1b; border-width: 1px; background-color: #282828; } + +notebook > header > tabs { margin: -1px; } + +notebook > header.top { border-bottom-style: solid; } + +notebook > header.top > tabs { margin-bottom: -2px; } + +notebook > header.top > tabs > tab:hover { box-shadow: inset 0 -4px #1b1b1b; } + +notebook > header.top > tabs > tab:checked { box-shadow: inset 0 -4px #15539e; } + +notebook > header.bottom { border-top-style: solid; } + +notebook > header.bottom > tabs { margin-top: -2px; } + +notebook > header.bottom > tabs > tab:hover { box-shadow: inset 0 4px #1b1b1b; } + +notebook > header.bottom > tabs > tab:checked { box-shadow: inset 0 4px #15539e; } + +notebook > header.left { border-right-style: solid; } + +notebook > header.left > tabs { margin-right: -2px; } + +notebook > header.left > tabs > tab:hover { box-shadow: inset -4px 0 #1b1b1b; } + +notebook > header.left > tabs > tab:checked { box-shadow: inset -4px 0 #15539e; } + +notebook > header.right { border-left-style: solid; } + +notebook > header.right > tabs { margin-left: -2px; } + +notebook > header.right > tabs > tab:hover { box-shadow: inset 4px 0 #1b1b1b; } + +notebook > header.right > tabs > tab:checked { box-shadow: inset 4px 0 #15539e; } + +notebook > header.top > tabs > arrow { border-top-style: none; } + +notebook > header.bottom > tabs > arrow { border-bottom-style: none; } + +notebook > header.top > tabs > arrow, notebook > header.bottom > tabs > arrow { margin-left: -5px; margin-right: -5px; padding-left: 4px; padding-right: 4px; } + +notebook > header.top > tabs > arrow.down, notebook > header.bottom > tabs > arrow.down { -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); } + +notebook > header.top > tabs > arrow.up, notebook > header.bottom > tabs > arrow.up { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } + +notebook > header.left > tabs > arrow { border-left-style: none; } + +notebook > header.right > tabs > arrow { border-right-style: none; } + +notebook > header.left > tabs > arrow, notebook > header.right > tabs > arrow { margin-top: -5px; margin-bottom: -5px; padding-top: 4px; padding-bottom: 4px; } + +notebook > header.left > tabs > arrow.down, notebook > header.right > tabs > arrow.down { -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); } + +notebook > header.left > tabs > arrow.up, notebook > header.right > tabs > arrow.up { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +notebook > header > tabs > arrow { min-height: 16px; min-width: 16px; border-radius: 0; } + +notebook > header > tabs > arrow:hover:not(:active):not(:backdrop) { background-clip: padding-box; background-image: none; background-color: rgba(255, 255, 255, 0.3); border-color: transparent; box-shadow: none; } + +notebook > header > tabs > arrow:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; } + +notebook > header > tabs > tab { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); min-height: 30px; min-width: 30px; padding: 3px 12px; color: #eeeeec; font-weight: normal; border-width: 1px; border-color: transparent; } + +notebook > header > tabs > tab:hover { color: #eeeeec; background-color: #1e1e1e; } + +notebook > header > tabs > tab.reorderable-page:hover { border-color: rgba(27, 27, 27, 0.3); background-color: rgba(53, 53, 53, 0.2); } + +notebook > header > tabs > tab:not(:checked) { outline-color: transparent; } + +notebook > header > tabs > tab:checked { color: #eeeeec; } + +notebook > header > tabs > tab.reorderable-page:checked { border-color: rgba(27, 27, 27, 0.5); background-color: rgba(53, 53, 53, 0.5); } + +notebook > header > tabs > tab.reorderable-page:checked:hover { background-color: rgba(53, 53, 53, 0.7); } + +notebook > header > tabs > tab button.flat { color: alpha(currentColor,0.3); padding: 0; margin-top: 4px; margin-bottom: 4px; min-width: 20px; min-height: 20px; } + +notebook > header > tabs > tab button.flat:hover { color: currentColor; } + +notebook > header > tabs > tab button.flat:last-child { margin-left: 4px; margin-right: -4px; } + +notebook > header > tabs > tab button.flat:first-child { margin-left: -4px; margin-right: 4px; } + +notebook > header.top > tabs, notebook > header.bottom > tabs { padding-left: 4px; padding-right: 4px; } + +notebook > header.top > tabs:not(:only-child), notebook > header.bottom > tabs:not(:only-child) { margin-left: 3px; margin-right: 3px; } + +notebook > header.top > tabs:not(:only-child):first-child, notebook > header.bottom > tabs:not(:only-child):first-child { margin-left: -1px; } + +notebook > header.top > tabs:not(:only-child):last-child, notebook > header.bottom > tabs:not(:only-child):last-child { margin-right: -1px; } + +notebook > header.top > tabs > tab, notebook > header.bottom > tabs > tab { margin-left: 4px; margin-right: 4px; } + +notebook > header.top > tabs > tab.reorderable-page, notebook > header.bottom > tabs > tab.reorderable-page { border-style: none solid; } + +notebook > header.left > tabs, notebook > header.right > tabs { padding-top: 4px; padding-bottom: 4px; } + +notebook > header.left > tabs:not(:only-child), notebook > header.right > tabs:not(:only-child) { margin-top: 3px; margin-bottom: 3px; } + +notebook > header.left > tabs:not(:only-child):first-child, notebook > header.right > tabs:not(:only-child):first-child { margin-top: -1px; } + +notebook > header.left > tabs:not(:only-child):last-child, notebook > header.right > tabs:not(:only-child):last-child { margin-bottom: -1px; } + +notebook > header.left > tabs > tab, notebook > header.right > tabs > tab { margin-top: 4px; margin-bottom: 4px; } + +notebook > header.left > tabs > tab.reorderable-page, notebook > header.right > tabs > tab.reorderable-page { border-style: solid none; } + +notebook > header.top > tabs > tab { padding-bottom: 4px; } + +notebook > header.bottom > tabs > tab { padding-top: 4px; } + +notebook > stack:not(:only-child) { background-color: #2d2d2d; } + +/************** Scrollbars * */ +scrollbar { background-color: #313131; transition: all 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +scrollbar.top { border-bottom: 1px solid #1b1b1b; } + +scrollbar.bottom { border-top: 1px solid #1b1b1b; } + +scrollbar.left { border-right: 1px solid #1b1b1b; } + +scrollbar.right { border-left: 1px solid #1b1b1b; } + +scrollbar > range > trough > slider { min-width: 8px; min-height: 8px; margin: -1px; border: 4px solid transparent; border-radius: 10px; background-clip: padding-box; background-color: #a4a4a3; transition: all 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +scrollbar > range > trough > slider:hover { background-color: #c9c9c7; } + +scrollbar > range > trough > slider:hover:active { background-color: #1b6acb; } + +scrollbar > range > trough > slider:disabled { background-color: transparent; } + +scrollbar > range.fine-tune > trough > slider { transition: none; min-width: 6px; min-height: 6px; } + +scrollbar > range.fine-tune.horizontal > trough > slider { border-width: 5px 4px; } + +scrollbar > range.fine-tune.vertical > trough > slider { border-width: 4px 5px; } + +scrollbar.overlay-indicator:not(.dragging):not(.hovering) { border-color: transparent; opacity: 0.4; background-color: transparent; } + +scrollbar.overlay-indicator:not(.dragging):not(.hovering) > range > trough > slider { margin: 0; min-width: 3px; min-height: 3px; background-color: #eeeeec; border: 1px solid black; } + +scrollbar.overlay-indicator.horizontal:not(.dragging):not(.hovering) > range > trough > slider { margin: 0 2px; min-width: 40px; } + +scrollbar.overlay-indicator.vertical:not(.dragging):not(.hovering) > range > trough > slider { margin: 2px 0; min-height: 40px; } + +scrollbar.overlay-indicator.dragging, scrollbar.overlay-indicator.hovering { opacity: 0.8; } + +scrollbar.horizontal > range > trough > slider { min-width: 40px; } + +scrollbar.vertical > range > trough > slider { min-height: 40px; } + +treeview ~ scrollbar.vertical { border-top: 1px solid #1b1b1b; margin-top: -1px; } + +/********** Switch * */ +switch { font-weight: bold; font-size: smaller; border: 1px solid #1b1b1b; border-radius: 14px; color: #eeeeec; background-color: #282828; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; /* only show i / o for the accessible theme */ } + +switch { outline: 0 solid transparent; outline-offset: 4px; } + +switch:focus:focus-visible { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: 0; } + +headerbar switch { background-color: #141414; } + +switch:checked { color: #ffffff; border-color: #030c17; background-color: #15539e; } + +switch:disabled { color: #919190; border-color: #1b1b1b; background-color: #323232; text-shadow: none; } + +switch > slider { color: #eeeeec; outline-color: rgba(21, 83, 158, 0.7); border-color: #1b1b1b; background-image: linear-gradient(to top, #373737 2px, #3a3a3a); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); margin: -1px; min-width: 24px; min-height: 24px; border: 1px solid; border-color: #1b1b1b; border-radius: 50%; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +switch > image { color: transparent; } + +switch:hover > slider { color: #eeeeec; border-color: #1b1b1b; background-image: linear-gradient(to top, #303030 20%, #323232 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +switch:checked > slider { border: 1px solid #030c17; } + +switch:disabled > slider { color: #919190; border-color: #202020; background-image: image(#323232); } + +row:selected switch { outline-color: rgba(255, 255, 255, 0.3); } + +/************************* Check and Radio items * */ +.view.content-view.check:not(list), iconview.content-view.check:not(list), .content-view .tile check:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #15539e; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:hover:not(list), iconview.content-view.check:hover:not(list), .content-view .tile check:hover:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #15539e; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:active:not(list), iconview.content-view.check:active:not(list), .content-view .tile check:active:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #15539e; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:backdrop:not(list), iconview.content-view.check:backdrop:not(list), .content-view .tile check:backdrop:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #5a5a5a; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:checked:not(list), iconview.content-view.check:checked:not(list), .content-view .tile check:checked:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: #15539e; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +.view.content-view.check:checked:hover:not(list), iconview.content-view.check:checked:hover:not(list), .content-view .tile check:checked:hover:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: #15539e; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +.view.content-view.check:checked:active:not(list), iconview.content-view.check:checked:active:not(list), .content-view .tile check:checked:active:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: #15539e; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +.view.content-view.check:backdrop:checked:not(list), iconview.content-view.check:backdrop:checked:not(list), .content-view .tile check:backdrop:checked:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: rgba(238, 238, 236, 0.8); background-color: #5a5a5a; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +checkbutton { border-spacing: 4px; border-radius: 5px; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +checkbutton { outline: 0 solid transparent; outline-offset: 4px; } + +checkbutton:focus:focus-visible { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: -2px; } + +checkbutton.text-button { padding: 4px; } + +check, radio { min-height: 14px; min-width: 14px; border: 1px solid; -gtk-icon-source: none; } + +check, radio { background-clip: padding-box; background-image: linear-gradient(to bottom, #424242 20%, #353535 90%); border-color: #070707; box-shadow: 0 1px rgba(0, 0, 0, 0.05); color: #ffffff; } + +check:hover, radio:hover { background-image: linear-gradient(to bottom, #4c4c4c 10%, #3f3f3f 90%); } + +check:active, radio:active { box-shadow: inset 0 1px black; background-image: image(#282828); } + +check:disabled, radio:disabled { box-shadow: none; color: rgba(255, 255, 255, 0.7); } + +check:checked, radio:checked { background-clip: border-box; background-image: linear-gradient(to bottom, #185fb4 20%, #15539e 90%); border-color: #092444; box-shadow: 0 1px rgba(0, 0, 0, 0.05); color: #ffffff; } + +check:checked:hover, radio:checked:hover { background-image: linear-gradient(to bottom, #1b68c6 10%, #185cb0 90%); } + +check:checked:active, radio:checked:active { box-shadow: inset 0 1px black; background-image: image(#124787); } + +check:checked:disabled, radio:checked:disabled { box-shadow: none; color: rgba(255, 255, 255, 0.7); } + +check:indeterminate, radio:indeterminate { background-clip: border-box; background-image: linear-gradient(to bottom, #185fb4 20%, #15539e 90%); border-color: #092444; box-shadow: 0 1px rgba(0, 0, 0, 0.05); color: #ffffff; } + +check:indeterminate:hover, radio:indeterminate:hover { background-image: linear-gradient(to bottom, #1b68c6 10%, #185cb0 90%); } + +check:indeterminate:active, radio:indeterminate:active { box-shadow: inset 0 1px black; background-image: image(#124787); } + +check:indeterminate:disabled, radio:indeterminate:disabled { box-shadow: none; color: rgba(255, 255, 255, 0.7); } + +.osd check, .osd radio { color: #eeeeec; outline-color: rgba(21, 83, 158, 0.7); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; } + +.osd check:hover, .osd radio:hover { color: #eeeeec; outline-color: rgba(21, 83, 158, 0.7); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; } + +.osd check:active, .osd radio:active { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; } + +.osd check:disabled, .osd radio:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; } + +check { border-radius: 3px; -gtk-icon-size: 14px; } + +check:checked { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets/check-symbolic.symbolic.png")), -gtk-recolor(url("assets/check@2-symbolic.symbolic.png"))); } + +check:indeterminate { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets/dash-symbolic.symbolic.png")), -gtk-recolor(url("assets/dash@2-symbolic.symbolic.png"))); } + +treeview.view radio:selected:focus, treeview.view radio:selected, radio { border-radius: 100%; -gtk-icon-size: 14px; } + +treeview.view radio:checked:selected, radio:checked { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets/bullet-symbolic.symbolic.png")), -gtk-recolor(url("assets/bullet@2-symbolic.symbolic.png"))); } + +treeview.view radio:indeterminate:selected, radio:indeterminate { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets/dash-symbolic.symbolic.png")), -gtk-recolor(url("assets/dash@2-symbolic.symbolic.png"))); } + +treeview.view check:selected:focus, treeview.view check:selected, treeview.view radio:selected:focus, treeview.view radio:selected { color: #ffffff; } + +/************ GtkScale * */ +progressbar > trough, scale > trough > fill, scale > trough { border: 1px solid #282828; border-radius: 3px; background-color: #282828; } + +headerbar progressbar > trough, headerbar scale > trough > fill, headerbar scale > trough { background-color: #141414; } + +progressbar > trough:disabled, scale > trough > fill:disabled, scale > trough:disabled { background-color: #323232; border-color: #202020; } + +row:selected progressbar > trough, row:selected scale > trough > fill, row:selected scale > trough { outline-color: rgba(255, 255, 255, 0.3); border-color: #030c17; } + +.osd progressbar > trough, .osd scale > trough > fill, .osd scale > trough { border-color: rgba(0, 0, 0, 0.7); background-color: rgba(0, 0, 0, 0.5); } + +.osd progressbar > trough:disabled, .osd scale > trough > fill:disabled, .osd scale > trough:disabled { background-color: rgba(58, 58, 57, 0.5); } + +progressbar > trough > progress, scale > trough > highlight { border: 1px solid #15539e; border-radius: 3px; background-color: #15539e; } + +progressbar > trough > progress:disabled, scale > trough > highlight:disabled { background-color: transparent; border-color: transparent; } + +row:selected progressbar > trough > progress, row:selected scale > trough > highlight { border-color: #030c17; } + +.osd progressbar > trough > progress, .osd scale > trough > highlight { border-color: rgba(0, 0, 0, 0.7); } + +.osd progressbar > trough > progress:disabled, .osd scale > trough > highlight:disabled { border-color: transparent; } + +scale { min-height: 10px; min-width: 10px; padding: 12px; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +scale > trough { outline: 0 solid transparent; outline-offset: 16px; } + +scale:focus:focus-visible > trough { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: 10px; } + +scale > trough { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +scale > trough > fill, scale > trough > highlight { margin: -1px; } + +scale > trough > slider { min-height: 18px; min-width: 18px; margin: -9px; } + +scale.fine-tune.horizontal { padding-top: 9px; padding-bottom: 9px; min-height: 16px; } + +scale.fine-tune.vertical { padding-left: 9px; padding-right: 9px; min-width: 16px; } + +scale.fine-tune > trough > slider { margin: -6px; } + +scale.fine-tune > trough > fill, scale.fine-tune > trough > highlight, scale.fine-tune > trough { border-radius: 5px; } + +scale > trough > fill:disabled { border-color: transparent; background-color: transparent; } + +.osd scale > trough > fill { background-color: rgba(91, 91, 90, 0.775); } + +.osd scale > trough > fill:disabled { border-color: transparent; background-color: transparent; } + +scale > trough > slider { color: #eeeeec; outline-color: rgba(21, 83, 158, 0.7); border-color: #1b1b1b; background-image: linear-gradient(to top, #373737 2px, #3a3a3a); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); border-width: 1px; border-style: solid; border-radius: 100%; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: background, border, box-shadow; } + +scale > trough > slider:hover { color: #eeeeec; border-color: #1b1b1b; background-image: linear-gradient(to top, #303030 20%, #323232 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +scale > trough > slider:active { border-color: #030c17; } + +scale > trough > slider:disabled { color: #919190; border-color: #202020; background-image: image(#323232); } + +row:selected scale > trough > slider:disabled, row:selected scale > trough > slider { border-color: #030c17; } + +.osd scale > trough > slider { color: #eeeeec; outline-color: rgba(21, 83, 158, 0.7); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; border-color: rgba(0, 0, 0, 0.7); background-color: #262626; } + +.osd scale > trough > slider:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(12, 12, 12, 0.7)); background-clip: padding-box; background-color: #262626; } + +.osd scale > trough > slider:active { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; background-color: #262626; } + +.osd scale > trough > slider:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; background-color: #262626; } + +scale > value { color: alpha(currentColor,0.55); font-feature-settings: "tnum"; } + +scale.horizontal > marks { color: alpha(currentColor,0.55); } + +scale.horizontal > marks.top { margin-bottom: 6px; } + +scale.horizontal > marks.bottom { margin-top: 6px; } + +scale.horizontal > marks indicator { background-color: currentColor; min-height: 6px; min-width: 1px; } + +scale.horizontal > value.left { margin-right: 9px; } + +scale.horizontal > value.right { margin-left: 9px; } + +scale.horizontal.fine-tune > marks.top { margin-top: 3px; } + +scale.horizontal.fine-tune > marks.bottom { margin-bottom: 3px; } + +scale.horizontal.fine-tune > marks indicator { min-height: 3px; } + +scale.vertical > marks { color: alpha(currentColor,0.55); } + +scale.vertical > marks.top { margin-right: 6px; } + +scale.vertical > marks.bottom { margin-left: 6px; } + +scale.vertical > marks indicator { background-color: currentColor; min-height: 1px; min-width: 6px; } + +scale.vertical > value.top { margin-bottom: 9px; } + +scale.vertical > value.bottom { margin-top: 9px; } + +scale.vertical.fine-tune > marks.top { margin-left: 3px; } + +scale.vertical.fine-tune > marks.bottom { margin-right: 3px; } + +scale.vertical.fine-tune > marks indicator { min-height: 3px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above-dark.png"), url("assets/slider-horz-scale-has-marks-above-dark@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above-hover-dark.png"), url("assets/slider-horz-scale-has-marks-above-hover-dark@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above-active-dark.png"), url("assets/slider-horz-scale-has-marks-above-active-dark@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above-insensitive-dark.png"), url("assets/slider-horz-scale-has-marks-above-insensitive-dark@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-below-dark.png"), url("assets/slider-horz-scale-has-marks-below-dark@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-below-hover-dark.png"), url("assets/slider-horz-scale-has-marks-below-hover-dark@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-below-active-dark.png"), url("assets/slider-horz-scale-has-marks-below-active-dark@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-below-insensitive-dark.png"), url("assets/slider-horz-scale-has-marks-below-insensitive-dark@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-above-dark.png"), url("assets/slider-vert-scale-has-marks-above-dark@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-above-hover-dark.png"), url("assets/slider-vert-scale-has-marks-above-hover-dark@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-above-active-dark.png"), url("assets/slider-vert-scale-has-marks-above-active-dark@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-above-insensitive-dark.png"), url("assets/slider-vert-scale-has-marks-above-insensitive-dark@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-below-dark.png"), url("assets/slider-vert-scale-has-marks-below-dark@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-below-hover-dark.png"), url("assets/slider-vert-scale-has-marks-below-hover-dark@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-below-active-dark.png"), url("assets/slider-vert-scale-has-marks-below-active-dark@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-below-insensitive-dark.png"), url("assets/slider-vert-scale-has-marks-below-insensitive-dark@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.color { min-height: 0; min-width: 0; } + +scale.color > trough { background-image: image(#1b1b1b); background-repeat: no-repeat; } + +scale.color.horizontal { padding: 0 0 15px 0; } + +scale.color.horizontal > trough { padding-bottom: 4px; background-position: 0 -3px; border-top-left-radius: 0; border-top-right-radius: 0; } + +scale.color.horizontal > trough > slider:dir(ltr):hover, scale.color.horizontal > trough > slider:dir(ltr):backdrop, scale.color.horizontal > trough > slider:dir(ltr):disabled, scale.color.horizontal > trough > slider:dir(ltr):backdrop:disabled, scale.color.horizontal > trough > slider:dir(ltr), scale.color.horizontal > trough > slider:dir(rtl):hover, scale.color.horizontal > trough > slider:dir(rtl):backdrop, scale.color.horizontal > trough > slider:dir(rtl):disabled, scale.color.horizontal > trough > slider:dir(rtl):backdrop:disabled, scale.color.horizontal > trough > slider:dir(rtl) { margin-bottom: -15px; margin-top: 6px; } + +scale.color.vertical:dir(ltr) { padding: 0 0 0 15px; } + +scale.color.vertical:dir(ltr) > trough { padding-left: 4px; background-position: 3px 0; border-bottom-right-radius: 0; border-top-right-radius: 0; } + +scale.color.vertical:dir(ltr) > trough > slider:hover, scale.color.vertical:dir(ltr) > trough > slider:backdrop, scale.color.vertical:dir(ltr) > trough > slider:disabled, scale.color.vertical:dir(ltr) > trough > slider:backdrop:disabled, scale.color.vertical:dir(ltr) > trough > slider { margin-left: -15px; margin-right: 6px; } + +scale.color.vertical:dir(rtl) { padding: 0 15px 0 0; } + +scale.color.vertical:dir(rtl) > trough { padding-right: 4px; background-position: -3px 0; border-bottom-left-radius: 0; border-top-left-radius: 0; } + +scale.color.vertical:dir(rtl) > trough > slider:hover, scale.color.vertical:dir(rtl) > trough > slider:backdrop, scale.color.vertical:dir(rtl) > trough > slider:disabled, scale.color.vertical:dir(rtl) > trough > slider:backdrop:disabled, scale.color.vertical:dir(rtl) > trough > slider { margin-right: -15px; margin-left: 6px; } + +scale.color.fine-tune.horizontal:dir(ltr), scale.color.fine-tune.horizontal:dir(rtl) { padding: 0 0 12px 0; } + +scale.color.fine-tune.horizontal:dir(ltr) > trough, scale.color.fine-tune.horizontal:dir(rtl) > trough { padding-bottom: 7px; background-position: 0 -6px; } + +scale.color.fine-tune.horizontal:dir(ltr) > trough > slider, scale.color.fine-tune.horizontal:dir(rtl) > trough > slider { margin-bottom: -15px; margin-top: 6px; } + +scale.color.fine-tune.vertical:dir(ltr) { padding: 0 0 0 12px; } + +scale.color.fine-tune.vertical:dir(ltr) > trough { padding-left: 7px; background-position: 6px 0; } + +scale.color.fine-tune.vertical:dir(ltr) > trough > slider { margin-left: -15px; margin-right: 6px; } + +scale.color.fine-tune.vertical:dir(rtl) { padding: 0 12px 0 0; } + +scale.color.fine-tune.vertical:dir(rtl) > trough { padding-right: 7px; background-position: -6px 0; } + +scale.color.fine-tune.vertical:dir(rtl) > trough > slider { margin-right: -15px; margin-left: 6px; } + +/***************** Progress bars * */ +progressbar { font-size: smaller; color: rgba(238, 238, 236, 0.4); font-feature-settings: "tnum"; } + +progressbar.horizontal > trough { min-width: 150px; } + +progressbar.horizontal > trough, progressbar.horizontal > trough > progress { min-height: 2px; } + +progressbar.vertical > trough { min-height: 80px; } + +progressbar.vertical > trough, progressbar.vertical > trough > progress { min-width: 2px; } + +progressbar.horizontal > trough > progress { margin: 0 -1px; } + +progressbar.vertical > trough > progress { margin: -1px 0; } + +progressbar > trough > progress { /* share most of scales' */ /* override insensitive that is specific to progress */ border-radius: 1.5px; } + +progressbar > trough > progress:disabled { background-color: #919190; border-color: #919190; } + +progressbar > trough > progress.left { border-top-left-radius: 5px; border-bottom-left-radius: 5px; } + +progressbar > trough > progress.right { border-top-right-radius: 5px; border-bottom-right-radius: 5px; } + +progressbar > trough > progress.top { border-top-right-radius: 5px; border-top-left-radius: 5px; } + +progressbar > trough > progress.bottom { border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; } + +progressbar.osd { min-width: 3px; min-height: 3px; background-color: transparent; } + +progressbar.osd > trough { border-style: none; border-radius: 0; background-color: transparent; box-shadow: none; } + +progressbar.osd > trough > progress { border-style: none; border-radius: 0; } + +progressbar > trough.empty > progress { all: unset; } + +/************* Level Bar * */ +levelbar.horizontal trough > block { min-height: 9px; border-radius: 5px; } + +levelbar.horizontal trough > block:dir(rtl) { border-radius: 0 5px 5px 0; } + +levelbar.horizontal trough > block:dir(ltr) { border-radius: 5px 0 0 5px; } + +levelbar.horizontal trough > block.empty, levelbar.horizontal trough > block.full { border-radius: 5px; } + +levelbar.horizontal.discrete trough > block { min-height: 2px; margin: 1px; min-width: 24px; border-radius: 0; } + +levelbar.horizontal.discrete trough > block:first-child { border-radius: 2px 0 0 2px; } + +levelbar.horizontal.discrete trough > block:last-child { border-radius: 0 2px 2px 0; } + +levelbar.vertical trough > block { min-width: 9px; border-radius: 5px; } + +levelbar.vertical.discrete > trough > block { min-width: 2px; margin: 1px 0; min-height: 32px; } + +levelbar > trough { padding: 0; } + +levelbar > trough > block { border: 1px solid; } + +levelbar > trough > block.low { border-color: #f57900; background-color: #f57900; } + +levelbar > trough > block.high, levelbar > trough > block:not(.empty) { border-color: #15539e; background-color: #15539e; } + +levelbar > trough > block.full { border-color: #26ab62; background-color: #26ab62; } + +levelbar > trough > block.empty { background-color: #282828; border-color: #282828; } + +/**************** Print dialog * */ +window.dialog.print drawing { color: #eeeeec; background: none; border: none; padding: 0; } + +window.dialog.print drawing paper { background: white; color: #2e3436; border: 1px solid #1b1b1b; } + +window.dialog.print .dialog-action-box { margin: 12px; } + +/********** Frames * */ +frame, .frame { border: 1px solid #1b1b1b; } + +frame { border-radius: 8px; } + +frame > label { margin: 4px; } + +actionbar > revealer > box { padding: 6px; border-top: 1px solid #1b1b1b; } + +actionbar > revealer > box, actionbar > revealer > box > box.start, actionbar > revealer > box > box.end { border-spacing: 6px; } + +scrolledwindow > overshoot.top { background-image: radial-gradient(farthest-side at top, #020202 85%, rgba(2, 2, 2, 0)), radial-gradient(farthest-side at top, rgba(238, 238, 236, 0.07), rgba(238, 238, 236, 0)); background-size: 100% 3%, 100% 50%; background-repeat: no-repeat; background-position: top; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > overshoot.bottom { background-image: radial-gradient(farthest-side at bottom, #020202 85%, rgba(2, 2, 2, 0)), radial-gradient(farthest-side at bottom, rgba(238, 238, 236, 0.07), rgba(238, 238, 236, 0)); background-size: 100% 3%, 100% 50%; background-repeat: no-repeat; background-position: bottom; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > overshoot.left { background-image: radial-gradient(farthest-side at left, #020202 85%, rgba(2, 2, 2, 0)), radial-gradient(farthest-side at left, rgba(238, 238, 236, 0.07), rgba(238, 238, 236, 0)); background-size: 3% 100%, 50% 100%; background-repeat: no-repeat; background-position: left; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > overshoot.right { background-image: radial-gradient(farthest-side at right, #020202 85%, rgba(2, 2, 2, 0)), radial-gradient(farthest-side at right, rgba(238, 238, 236, 0.07), rgba(238, 238, 236, 0)); background-size: 3% 100%, 50% 100%; background-repeat: no-repeat; background-position: right; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > junction { background: #1b1b1b, linear-gradient(to bottom, transparent 1px, #313131 1px), linear-gradient(to right, transparent 1px, #313131 1px); } + +scrolledwindow > junction:dir(rtl) { background: #1b1b1b, linear-gradient(to bottom, transparent 1px, #313131 1px), linear-gradient(to left, transparent 1px, #313131 1px); } + +separator { background: #282828; min-width: 1px; min-height: 1px; } + +/********* Lists * */ +listview, list { color: white; background-color: #2d2d2d; border-color: #1b1b1b; } + +listview:backdrop, list:backdrop { color: #d6d6d6; background-color: #303030; border-color: #202020; } + +listview > row, list > row { padding: 2px; } + +listview > row.expander, list > row.expander { padding: 0px; } + +listview > row.expander .row-header, list > row.expander .row-header { padding: 2px; } + +listview.horizontal row.separator, listview.separators.horizontal > row:not(.separator), list.horizontal row.separator, list.separators.horizontal > row:not(.separator) { border-left: 1px solid #545453; } + +listview:not(.horizontal) row.separator, listview.separators:not(.horizontal) > row:not(.separator), list:not(.horizontal) row.separator, list.separators:not(.horizontal) > row:not(.separator) { border-bottom: 1px solid #545453; } + +row { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +row { outline: 0 solid transparent; outline-offset: 4px; } + +row:focus:focus-visible { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: -2px; } + +row.activatable.has-open-popup, row.activatable:hover { background-color: rgba(238, 238, 236, 0.05); } + +row.activatable:active { box-shadow: inset 0 2px 2px -2px rgba(0, 0, 0, 0.2); } + +row.activatable:selected:active { box-shadow: inset 0 2px 3px -1px rgba(0, 0, 0, 0.5); } + +row.activatable.has-open-popup:selected, row.activatable:selected:hover { background-color: #2b62a6; } + +row:selected { outline-color: rgba(255, 255, 255, 0.3); } + +columnview > listview > row { padding: 0; } + +columnview > listview > row > cell { padding: 8px 6px; } + +columnview > listview > row > cell:not(:first-child) { border-left: 1px solid transparent; } + +columnview.column-separators > listview > row > cell { border-left-color: #545453; } + +columnview.data-table > listview > row > cell { padding-top: 2px; padding-bottom: 2px; } + +treeexpander { border-spacing: 4px; } + +/******************************************************** Data Tables * treeview like tables with individual focusable cells * https://gitlab.gnome.org/GNOME/gtk/-/issues/2929 * */ +columnview row:not(:selected) cell editablelabel:not(.editing):focus-within { outline: 2px solid rgba(21, 83, 158, 0.7); } + +columnview row:not(:selected) cell editablelabel.editing:focus-within { outline: 2px solid #15539e; } + +columnview row:not(:selected) cell editablelabel.editing text selection { color: #ffffff; background-color: #15539e; } + +/******************************************************* Rich Lists * Large list usually containing lots of widgets * https://gitlab.gnome.org/GNOME/gtk/-/issues/3073 * */ +.rich-list { /* rich lists usually containing other widgets than just labels/text */ } + +.rich-list > row { padding: 8px 12px; min-height: 32px; /* should be tall even when only containing a label */ } + +.rich-list > row > box { border-spacing: 12px; } + +/********************* App Notifications * */ +.app-notification { padding: 10px; border-spacing: 10px; border-radius: 0 0 5px 5px; background-color: rgba(38, 38, 38, 0.7); background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.2), transparent 2px); background-clip: padding-box; } + +.app-notification border { border: none; } + +/************* Expanders * */ +expander { min-width: 16px; min-height: 16px; -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } + +expander:dir(rtl) { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl"); } + +expander:disabled { color: #919190; } + +expander:checked { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +expander-widget { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +expander-widget > box > title { outline: 0 solid transparent; outline-offset: 4px; } + +expander-widget:focus:focus-visible > box > title { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: -2px; } + +expander-widget > box > title { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); border-radius: 5px; } + +expander-widget > box > title:hover > expander { color: white; } + +.navigation-sidebar:not(decoration):not(window):drop(active):focus, .navigation-sidebar:not(decoration):not(window):drop(active), placessidebar:not(decoration):not(window):drop(active):focus, placessidebar:not(decoration):not(window):drop(active), stackswitcher:not(decoration):not(window):drop(active):focus, stackswitcher:not(decoration):not(window):drop(active), expander-widget:not(decoration):not(window):drop(active):focus, expander-widget:not(decoration):not(window):drop(active) { box-shadow: none; } + +/************ Calendar * */ +calendar { color: white; border: 1px solid #1b1b1b; } + +calendar > header { border-bottom: 1px solid #1b1b1b; } + +calendar > header > button { border: none; box-shadow: none; background: none; border-radius: 0; } + +calendar > header > button:backdrop { background: none; } + +calendar > grid > label.today { box-shadow: inset 0px -2px #1b1b1b; } + +calendar > grid > label.today:selected { box-shadow: none; } + +calendar > grid > label:focus { outline-color: rgba(21, 83, 158, 0.7); outline-offset: -2px; outline-width: 2px; outline-style: solid; } + +calendar > grid > label.day-number { padding: 4px; } + +calendar > grid > label.day-number:selected { border-radius: 3px; } + +calendar > grid > label.day-number.other-month { color: alpha(currentColor,0.3); } + +/*********** Dialogs * */ +window.dialog.message .titlebar { min-height: 20px; background-image: none; background-color: #353535; border-style: none; border-top-left-radius: 7px; border-top-right-radius: 7px; } + +window.dialog.message box.dialog-vbox.vertical { border-spacing: 10px; } + +window.dialog.message label.title { font-weight: 800; font-size: 15pt; } + +window.dialog.message.csd.background { border-bottom-left-radius: 9px; border-bottom-right-radius: 9px; } + +window.dialog.message.csd .dialog-action-area button { padding: 10px 14px; border-radius: 0; border-left-style: solid; border-right-style: none; border-bottom-style: none; } + +window.dialog.message.csd .dialog-action-area button:first-child { border-left-style: none; border-bottom-left-radius: 7px; } + +window.dialog.message.csd .dialog-action-area button:last-child { border-bottom-right-radius: 7px; } + +filechooser .dialog-action-box { border-top: 1px solid #1b1b1b; } + +filechooser #pathbarbox { border-bottom: 1px solid #353535; } + +filechooserbutton > button > box { border-spacing: 6px; } + +filechooserbutton:drop(active) { box-shadow: none; border-color: transparent; } + +/*********** Sidebar * */ +.sidebar { background-color: #313131; } + +.sidebar:not(separator):dir(ltr), .sidebar.left:not(separator), .sidebar.left:not(separator):dir(rtl) { border-right: 1px solid #1b1b1b; border-left-style: none; } + +.sidebar:not(separator):dir(rtl), .sidebar.right:not(separator) { border-left: 1px solid #1b1b1b; border-right-style: none; } + +.sidebar listview.view, .sidebar list { background-color: transparent; } + +paned .sidebar.left, paned .sidebar.right, paned .sidebar.left:dir(rtl), paned .sidebar:dir(rtl), paned .sidebar:dir(ltr), paned .sidebar { border-style: none; } + +stacksidebar list.separators:not(.horizontal) > row:not(.separator) { border-bottom: none; } + +stacksidebar row { padding: 10px 4px; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +stacksidebar row { outline: 0 solid transparent; outline-offset: 4px; } + +stacksidebar row:focus:focus-visible { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: -2px; } + +stacksidebar row > label { padding-left: 6px; padding-right: 6px; } + +stacksidebar row.needs-attention > label { background-size: 6px 6px, 0 0; } + +stacksidebar row:selected { background-color: #202020; border-radius: 5px; color: #eeeeec; } + +stacksidebar row:selected:hover:dir(ltr), stacksidebar row:selected:hover:dir(rtl) { background-color: #141414; } + +stacksidebar row.activatable:active, stacksidebar row.activatable:selected:active { box-shadow: none; } + +separator.sidebar { background-color: #1b1b1b; } + +/********************** Navigation Sidebar * */ +.navigation-sidebar { padding: 5px 0; } + +.navigation-sidebar > separator { margin: 5px; } + +.navigation-sidebar > row { min-height: 36px; padding: 0 8px; border-radius: 5px; margin: 0 5px 2px; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +.navigation-sidebar > row { outline: 0 solid transparent; outline-offset: 4px; } + +.navigation-sidebar > row:focus-visible:focus-within { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: -2px; } + +.navigation-sidebar > row:hover { background-color: #141414; } + +.navigation-sidebar > row:selected { background-color: #202020; color: inherit; } + +.navigation-sidebar > row:selected:hover { background-color: #141414; } + +.navigation-sidebar > row:disabled { color: #919190; } + +/**************** File chooser * */ +row image.sidebar-icon { opacity: 0.7; } + +/* this should be more generic, only using .navigation-sidebar https://gitlab.gnome.org/GNOME/gtk/-/issues/2929 */ +placessidebar .navigation-sidebar > row { padding: 0; } + +placessidebar .navigation-sidebar > row > revealer { padding: 0 14px; } + +placessidebar .navigation-sidebar > row image.sidebar-icon:dir(ltr) { padding-right: 8px; } + +placessidebar .navigation-sidebar > row image.sidebar-icon:dir(rtl) { padding-left: 8px; } + +placessidebar .navigation-sidebar > row label.sidebar-label:dir(ltr) { padding-right: 2px; } + +placessidebar .navigation-sidebar > row label.sidebar-label:dir(rtl) { padding-left: 2px; } + +button.sidebar-button { min-height: 26px; min-width: 26px; margin-top: 3px; margin-bottom: 3px; padding: 0; border-radius: 100%; } + +placessidebar .navigation-sidebar > row:selected:active { box-shadow: none; } + +placessidebar .navigation-sidebar > row.sidebar-placeholder-row { padding: 0 8px; min-height: 2px; background-image: image(#26a269); background-clip: content-box; } + +placessidebar .navigation-sidebar > row.sidebar-new-bookmark-row { color: #15539e; } + +placessidebar .navigation-sidebar > row:drop(active):not(:disabled) { color: #26a269; box-shadow: inset 0 1px #26a269, inset 0 -1px #26a269; } + +placessidebar .navigation-sidebar > row:drop(active):not(:disabled):selected { color: #ffffff; background-color: #26a269; } + +placesview .server-list-button > image { transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -gtk-icon-transform: rotate(0turn); } + +placesview .server-list-button:checked > image { transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -gtk-icon-transform: rotate(-0.5turn); } + +placesview > actionbar > revealer > box > box { border-spacing: 6px; } + +/********* Paned * */ +paned > separator { min-width: 1px; min-height: 1px; -gtk-icon-source: none; border-style: none; background-color: transparent; background-image: image(#1b1b1b); background-size: 1px 1px; } + +paned > separator:selected { background-image: image(#15539e); } + +paned > separator.wide { min-width: 5px; min-height: 5px; background-color: #353535; background-image: image(#1b1b1b), image(#1b1b1b); background-size: 1px 1px, 1px 1px; } + +paned.horizontal > separator { background-repeat: repeat-y; } + +paned.horizontal > separator:dir(ltr) { margin: 0 -8px 0 0; padding: 0 8px 0 0; background-position: left; } + +paned.horizontal > separator:dir(rtl) { margin: 0 0 0 -8px; padding: 0 0 0 8px; background-position: right; } + +paned.horizontal > separator.wide { margin: 0; padding: 0; background-repeat: repeat-y, repeat-y; background-position: left, right; } + +paned.vertical > separator { margin: 0 0 -8px 0; padding: 0 0 8px 0; background-repeat: repeat-x; background-position: top; } + +paned.vertical > separator.wide { margin: 0; padding: 0; background-repeat: repeat-x, repeat-x; background-position: bottom, top; } + +/************** GtkVideo * */ +video { background: black; } + +video image.osd { min-width: 64px; min-height: 64px; border-radius: 32px; } + +/************ Tooltips * */ +tooltip { padding: 6px 10px; border-radius: 8px; box-shadow: none; } + +tooltip.background { background-color: rgba(0, 0, 0, 0.8); background-clip: padding-box; border: 1px solid rgba(255, 255, 255, 0.1); color: white; } + +tooltip > box { border-spacing: 6px; } + +/***************** Color Chooser * */ +colorswatch { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +colorswatch { outline: 0 solid transparent; outline-offset: 6px; } + +colorswatch:focus:focus-visible { outline-color: rgba(21, 83, 158, 0.7); outline-width: 4px; outline-offset: -2px; } + +colorswatch:drop(active), colorswatch { border-style: none; } + +colorswatch.top { border-top-left-radius: 5.5px; border-top-right-radius: 5.5px; } + +colorswatch.top > overlay { border-top-left-radius: 5px; border-top-right-radius: 5px; } + +colorswatch.bottom { border-bottom-left-radius: 5.5px; border-bottom-right-radius: 5.5px; } + +colorswatch.bottom > overlay { border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } + +colorswatch.left, colorswatch:first-child:not(.top) { border-top-left-radius: 5.5px; border-bottom-left-radius: 5.5px; } + +colorswatch.left > overlay, colorswatch:first-child:not(.top) > overlay { border-top-left-radius: 5px; border-bottom-left-radius: 5px; } + +colorswatch.right, colorswatch:last-child:not(.bottom) { border-top-right-radius: 5.5px; border-bottom-right-radius: 5.5px; } + +colorswatch.right > overlay, colorswatch:last-child:not(.bottom) > overlay { border-top-right-radius: 5px; border-bottom-right-radius: 5px; } + +colorswatch.dark > overlay { color: white; } + +colorswatch.dark.activatable:hover > overlay { border-color: #1b1b1b; } + +colorswatch.light > overlay { color: black; } + +colorswatch.light.activatable:hover > overlay { border-color: #1b1b1b; } + +colorswatch:drop(active) { box-shadow: none; } + +colorswatch.light:drop(active) > overlay { border-color: #26a269; box-shadow: inset 0 0 0 2px #1b1b1b, inset 0 0 0 1px #26a269; } + +colorswatch.dark:drop(active) > overlay { border-color: #26a269; box-shadow: inset 0 0 0 2px #1b1b1b, inset 0 0 0 1px #26a269; } + +colorswatch > overlay { border: 1px solid #1b1b1b; } + +colorswatch.activatable:hover > overlay { box-shadow: inset 0 1px rgba(255, 255, 255, 0.4), inset 0 -1px rgba(0, 0, 0, 0.2); } + +colorswatch#add-color-button { border-radius: 5px 0 0 5px; } + +colorswatch#add-color-button:only-child { border-radius: 5px; } + +colorswatch#add-color-button > overlay { color: #eeeeec; outline-color: rgba(21, 83, 158, 0.7); border-color: #1b1b1b; background-image: linear-gradient(to top, #373737 2px, #3a3a3a); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +colorswatch#add-color-button.activatable:hover > overlay { color: #eeeeec; border-color: #1b1b1b; background-image: linear-gradient(to top, #303030 20%, #323232 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +colorswatch:disabled { opacity: 0.5; } + +colorswatch:disabled > overlay { border-color: rgba(0, 0, 0, 0.6); box-shadow: none; } + +row:selected colorswatch { box-shadow: 0 0 0 2px #ffffff; } + +colorswatch#editor-color-sample { border-radius: 4px; } + +colorswatch#editor-color-sample > overlay { border-radius: 4.5px; } + +plane { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +plane { outline: 0 solid transparent; outline-offset: 6px; } + +plane:focus:focus-visible { outline-color: rgba(21, 83, 158, 0.7); outline-width: 2px; outline-offset: 2px; } + +colorchooser .popover.osd { border-radius: 5px; } + +/******** Misc * */ +.content-view { background-color: #232323; } + +.content-view:hover { -gtk-icon-filter: brightness(1.2); } + +.content-view .tile { margin: 2px; background-color: black; border-radius: 0; padding: 0; } + +.content-view .tile:active, .content-view .tile:selected { background-color: #15539e; } + +.content-view .tile:disabled { background-color: #323232; } + +.osd .scale-popup button.flat { border-style: none; border-radius: 5px; } + +.scale-popup button:hover { background-color: rgba(238, 238, 236, 0.1); border-radius: 5px; } + +/********************** Window Decorations * */ +window { border-width: 0px; } + +window.csd { box-shadow: 0 3px 9px 1px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(0, 0, 0, 0.75); margin: 0px; border-radius: 8px 8px 0 0; } + +window.csd:backdrop { box-shadow: 0 3px 9px 1px transparent, 0 2px 6px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.75); transition: 200ms ease-out; } + +window.csd.popup { border-radius: 5px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.65); } + +window.csd.dialog.message { border-radius: 8px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.65); } + +window.solid-csd { margin: 0; padding: 4px; border: solid 1px #1b1b1b; border-radius: 0; box-shadow: inset 0 0 0 4px #1b1b1b, inset 0 0 0 3px #2d2d2d, inset 0 1px rgba(238, 238, 236, 0.07); } + +window.solid-csd:backdrop { box-shadow: inset 0 0 0 4px #1b1b1b, inset 0 0 0 3px #353535, inset 0 1px rgba(238, 238, 236, 0.07); } + +window.maximized, window.fullscreen { border-radius: 0; box-shadow: none; } + +window.tiled, window.tiled-top, window.tiled-left, window.tiled-right, window.tiled-bottom { border-radius: 0; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.75), 0 0 0 20px transparent; } + +window:backdrop { box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.75), 0 0 0 20px transparent; } + +window.popup { box-shadow: none; } + +window.ssd { box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.75); } + +tooltip.csd { border-radius: 5px; box-shadow: none; } + +.view:selected:focus, .view:selected, textview > text:selected:focus, textview > text:selected, textview > text > selection:focus, textview > text > selection, iconview:selected:focus, iconview:selected, flowbox > flowboxchild:selected, gridview > child:selected, entry > text > selection, modelbutton.flat:selected, spinbutton:not(.vertical) > text > selection, spinbutton.vertical > text > text > selection, spinbutton.vertical > text > selection, columnview.view:selected:focus, columnview.view:selected, treeview.view:selected:focus, treeview.view:selected, row:selected, calendar > grid > label.day-number:selected { background-color: #15539e; } + +label:selected, .view:selected:focus, .view:selected, textview > text:selected:focus, textview > text:selected, textview > text > selection:focus, textview > text > selection, iconview:selected:focus, iconview:selected, flowbox > flowboxchild:selected, gridview > child:selected, entry > text > selection, modelbutton.flat:selected, spinbutton:not(.vertical) > text > selection, spinbutton.vertical > text > text > selection, spinbutton.vertical > text > selection, columnview.view:selected:focus, columnview.view:selected, treeview.view:selected:focus, treeview.view:selected, row:selected, calendar > grid > label.day-number:selected { color: #ffffff; } + +label:disabled > selection, label:disabled:selected, .view:disabled:selected, textview > text:disabled:selected:focus, textview > text:disabled:selected, textview > text > selection:disabled, iconview:disabled:selected:focus, iconview:disabled:selected, flowbox > flowboxchild:disabled:selected, gridview > child:disabled:selected, entry > text > selection:disabled, modelbutton.flat:disabled:selected, spinbutton:not(.vertical) > text > selection:disabled, spinbutton.vertical > text > text > selection:disabled, spinbutton.vertical > text > selection:disabled, columnview.view:disabled:selected, treeview.view:disabled:selected, row:disabled:selected, calendar > grid > label.day-number:disabled:selected { color: #8aa9ce; } + +.monospace { font-family: monospace; } + +/********************** Touch Copy & Paste * */ +cursor-handle { background-color: transparent; background-image: none; box-shadow: none; border-style: none; min-width: 20px; min-height: 24px; padding-left: 20px; padding-right: 20px; padding-top: 24px; padding-bottom: 24px; } + +cursor-handle.top:dir(ltr), cursor-handle.bottom:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/text-select-start-dark.png"), url("assets/text-select-start-dark@2.png")); } + +cursor-handle.bottom:dir(ltr), cursor-handle.top:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/text-select-end-dark.png"), url("assets/text-select-end-dark@2.png")); } + +cursor-handle.insertion-cursor:dir(ltr), cursor-handle.insertion-cursor:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above-dark.png"), url("assets/slider-horz-scale-has-marks-above-dark@2.png")); } + +cursor-handle.top:hover:dir(ltr), cursor-handle.bottom:hover:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/text-select-start-hover-dark.png"), url("assets/text-select-start-hover-dark@2.png")); } + +cursor-handle.bottom:hover:dir(ltr), cursor-handle.top:hover:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/text-select-end-hover-dark.png"), url("assets/text-select-end-hover-dark@2.png")); } + +cursor-handle.insertion-cursor:hover:dir(ltr), cursor-handle.insertion-cursor:hover:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above-hover-dark.png"), url("assets/slider-horz-scale-has-marks-above-hover-dark@2.png")); } + +cursor-handle.top:active:dir(ltr), cursor-handle.bottom:active:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/text-select-start-active-dark.png"), url("assets/text-select-start-active-dark@2.png")); } + +cursor-handle.bottom:active:dir(ltr), cursor-handle.top:active:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/text-select-end-active-dark.png"), url("assets/text-select-end-active-dark@2.png")); } + +cursor-handle.insertion-cursor:active:dir(ltr), cursor-handle.insertion-cursor:active:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above-active-dark.png"), url("assets/slider-horz-scale-has-marks-above-active-dark@2.png")); } + +shortcuts-section { margin: 20px; } + +.shortcuts-search-results { margin: 20px; border-spacing: 24px; } + +shortcut { border-spacing: 6px; } + +shortcut > .keycap { min-width: 20px; min-height: 25px; margin-top: 2px; padding-bottom: 3px; padding-left: 6px; padding-right: 6px; color: #eeeeec; background-color: #2d2d2d; border: 1px solid; border-color: #1b1b1b; border-radius: 5px; box-shadow: inset 0 -3px #222222; font-size: smaller; } + +:not(decoration):not(window):drop(active):focus, :not(decoration):not(window):drop(active) { border-color: #26a269; box-shadow: inset 0 0 0 1px #26a269; caret-color: #26a269; } + +stackswitcher > button.text-button { min-width: 100px; } + +stackswitcher.circular { border-spacing: 12px; } + +stackswitcher.circular > button.circular, stackswitcher.circular > button.text-button.circular { min-width: 32px; min-height: 32px; padding: 0; } + +/************* App Icons * */ +/* Outline for low res icons */ +.lowres-icon { -gtk-icon-shadow: 0 -1px rgba(0, 0, 0, 0.05), 1px 0 rgba(0, 0, 0, 0.1), 0 1px rgba(0, 0, 0, 0.3), -1px 0 rgba(0, 0, 0, 0.1); } + +/* Drapshadow for large icons */ +.icon-dropshadow { -gtk-icon-shadow: 0 1px 12px rgba(0, 0, 0, 0.05), 0 -1px rgba(0, 0, 0, 0.05), 1px 0 rgba(0, 0, 0, 0.1), 0 1px rgba(0, 0, 0, 0.3), -1px 0 rgba(0, 0, 0, 0.1); } + +/********* Emoji * */ +popover.emoji-picker > contents { padding: 0; } + +.emoji-searchbar { padding: 6px; border-spacing: 6px; border-bottom: 1px solid #1b1b1b; } + +.emoji-toolbar { padding: 6px; border-spacing: 6px; border-top: 1px solid #1b1b1b; } + +button.emoji-section { border-color: transparent; border-width: 3px; border-style: none none solid; border-radius: 0; padding: 3px 0 0; min-width: 32px; min-height: 28px; /* reset props inherited from the button style */ background: none; box-shadow: none; text-shadow: none; } + +button.emoji-section:hover { border-color: rgba(238, 238, 236, 0.1); } + +button.emoji-section:checked { border-color: #15539e; } + +popover.emoji-picker emoji { font-size: x-large; padding: 6px; border-radius: 6px; } + +popover.emoji-picker emoji:focus, popover.emoji-picker emoji:hover { background: #15539e; } + +emoji-completion-row > box { border-spacing: 10px; padding: 2px 10px; } + +emoji-completion-row:focus, emoji-completion-row:hover { background-color: #15539e; color: #ffffff; } + +emoji-completion-row emoji:focus, emoji-completion-row emoji:hover { background-color: #202020; } + +popover.entry-completion > contents { padding: 0; } + +statusbar { padding: 6px 10px 6px 10px; } + +menubutton > button > box { border-spacing: 6px; } + +menubutton arrow { min-height: 16px; min-width: 16px; } + +menubutton arrow.none { -gtk-icon-source: -gtk-icontheme("open-menu-symbolic"); } + +menubutton arrow.down { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +menubutton arrow.up { -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); } + +menubutton arrow.left { -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); } + +menubutton arrow.right { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } + +/* GTK NAMED COLORS ---------------- use responsibly! */ +/* +widget text/foreground color */ +@define-color theme_fg_color #eeeeec; +/* +text color for entries, views and content in general */ +@define-color theme_text_color white; +/* +widget base background color */ +@define-color theme_bg_color #353535; +/* +text widgets and the like base background color */ +@define-color theme_base_color #2d2d2d; +/* +base background color of selections */ +@define-color theme_selected_bg_color #15539e; +/* +text/foreground color of selections */ +@define-color theme_selected_fg_color #ffffff; +/* +base background color of insensitive widgets */ +@define-color insensitive_bg_color #323232; +/* +text foreground color of insensitive widgets */ +@define-color insensitive_fg_color #919190; +/* +insensitive text widgets and the like base background color */ +@define-color insensitive_base_color #2d2d2d; +/* +widget text/foreground color on backdrop windows */ +@define-color theme_unfocused_fg_color #919190; +/* +text color for entries, views and content in general on backdrop windows */ +@define-color theme_unfocused_text_color white; +/* +widget base background color on backdrop windows */ +@define-color theme_unfocused_bg_color #353535; +/* +text widgets and the like base background color on backdrop windows */ +@define-color theme_unfocused_base_color #303030; +/* +base background color of selections on backdrop windows */ +@define-color theme_unfocused_selected_bg_color #15539e; +/* +text/foreground color of selections on backdrop windows */ +@define-color theme_unfocused_selected_fg_color #ffffff; +/* +insensitive color on backdrop windows*/ +@define-color unfocused_insensitive_color #5b5b5b; +/* +widgets main borders color */ +@define-color borders #1b1b1b; +/* +widgets main borders color on backdrop windows */ +@define-color unfocused_borders #202020; +/* +these are pretty self explicative */ +@define-color warning_color #f57900; +@define-color error_color #cc0000; +@define-color success_color #26ab62; +/* +these colors are exported for the window manager and shouldn't be used in applications, +read if you used those and something break with a version upgrade you're on your own... */ +@define-color wm_title shade(#eeeeec, 1.8); +@define-color wm_unfocused_title #919190; +@define-color wm_highlight rgba(0, 0, 0, 0); +@define-color wm_borders_edge rgba(238, 238, 236, 0.07); +@define-color wm_bg_a shade(#353535, 1.2); +@define-color wm_bg_b #353535; +@define-color wm_shadow alpha(black, 0.35); +@define-color wm_border alpha(black, 0.18); +@define-color wm_button_hover_color_a shade(#353535, 1.3); +@define-color wm_button_hover_color_b #353535; +@define-color wm_button_active_color_a shade(#353535, 0.85); +@define-color wm_button_active_color_b shade(#353535, 0.89); +@define-color wm_button_active_color_c shade(#353535, 0.9); +/* content view background such as thumbnails view in Photos or Boxes */ +@define-color content_view_bg #2d2d2d; +/* Very contrasty background for text views (@theme_text_color foreground) */ +@define-color text_view_bg #1e1e1e; diff --cc gtk/theme/Default/Default-hc-dark.css index d8564f173a,0000000000..23752c4a68 mode 100644,000000..100644 --- a/gtk/theme/Default/Default-hc-dark.css +++ b/gtk/theme/Default/Default-hc-dark.css @@@ -1,1857 -1,0 +1,1847 @@@ +/* GTK NAMED COLORS ---------------- use responsibly! */ +/* +widget text/foreground color */ +@define-color theme_fg_color #f3f3f1; +/* +text color for entries, views and content in general */ +@define-color theme_text_color white; +/* +widget base background color */ +@define-color theme_bg_color #303030; +/* +text widgets and the like base background color */ +@define-color theme_base_color #2d2d2d; +/* +base background color of selections */ +@define-color theme_selected_bg_color #0f3b71; +/* +text/foreground color of selections */ +@define-color theme_selected_fg_color #ffffff; +/* +base background color of insensitive widgets */ +@define-color insensitive_bg_color #2f2f2f; +/* +text foreground color of insensitive widgets */ +@define-color insensitive_fg_color #919191; +/* +insensitive text widgets and the like base background color */ +@define-color insensitive_base_color #2d2d2d; +/* +widget text/foreground color on backdrop windows */ +@define-color theme_unfocused_fg_color #919190; +/* +text color for entries, views and content in general on backdrop windows */ +@define-color theme_unfocused_text_color white; +/* +widget base background color on backdrop windows */ +@define-color theme_unfocused_bg_color #353535; +/* +text widgets and the like base background color on backdrop windows */ +@define-color theme_unfocused_base_color #303030; +/* +base background color of selections on backdrop windows */ +@define-color theme_unfocused_selected_bg_color #0f3b71; +/* +text/foreground color of selections on backdrop windows */ +@define-color theme_unfocused_selected_fg_color #ffffff; +/* +insensitive color on backdrop windows*/ +@define-color unfocused_insensitive_color #5b5b5b; +/* +widgets main borders color */ +@define-color borders #686868; +/* +widgets main borders color on backdrop windows */ +@define-color unfocused_borders #202020; +/* +these are pretty self explicative */ +@define-color warning_color #f57900; +@define-color error_color #cc0000; +@define-color success_color #26ab62; +/* +these colors are exported for the window manager and shouldn't be used in applications, +read if you used those and something break with a version upgrade you're on your own... */ +@define-color wm_title shade(#f3f3f1, 1.8); +@define-color wm_unfocused_title #919190; +@define-color wm_highlight rgba(0, 0, 0, 0); +@define-color wm_borders_edge rgba(238, 238, 236, 0.07); +@define-color wm_bg_a shade(#303030, 1.2); +@define-color wm_bg_b #303030; +@define-color wm_shadow alpha(black, 0.35); +@define-color wm_border alpha(black, 0.18); +@define-color wm_button_hover_color_a shade(#303030, 1.3); +@define-color wm_button_hover_color_b #303030; +@define-color wm_button_active_color_a shade(#303030, 0.85); +@define-color wm_button_active_color_b shade(#303030, 0.89); +@define-color wm_button_active_color_c shade(#303030, 0.9); +/* content view background such as thumbnails view in Photos or Boxes */ +@define-color content_view_bg #2d2d2d; +/* Very contrasty background for text views (@theme_text_color foreground) */ +@define-color text_view_bg #1e1e1e; +/*************************** Check and Radio buttons * */ +/*************** Base States * */ +.background { color: #f3f3f1; background-color: #303030; } + +.background:backdrop { text-shadow: none; -gtk-icon-shadow: none; } + +dnd { color: #f3f3f1; } + +.normal-icons { -gtk-icon-size: 16px; } + +.large-icons { -gtk-icon-size: 32px; } + +image:disabled { -gtk-icon-filter: opacity(0.5); } + +.view, iconview, textview > text { color: white; background-color: #2d2d2d; } + +.view:disabled, iconview:disabled, textview > text:disabled { color: #919191; background-color: #2f2f2f; } + +.view:selected:focus, iconview:selected:focus, .view:selected, iconview:selected, textview > text:selected:focus, textview > text:selected { border-radius: 3px; } + +textview:drop(active) { caret-color: #26a269; } + +textview > border { background-color: #2e2e2e; } + +iconview { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +iconview { outline: 0 solid transparent; outline-offset: 4px; } + +iconview:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +iconview:drop(active) { box-shadow: none; } + +iconview > dndtarget:drop(active) { border-style: solid; border-width: 1px; border-color: black; } + +rubberband, .content-view > rubberband, columnview.view > rubberband, treeview.view > rubberband, gridview > rubberband, flowbox > rubberband { border: 1px solid #092444; background-color: rgba(9, 36, 68, 0.2); } + +flowbox > flowboxchild { padding: 3px; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +flowbox > flowboxchild { outline: 0 solid transparent; outline-offset: 4px; } + +flowbox > flowboxchild:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +flowbox > flowboxchild:selected { outline-color: rgba(255, 255, 255, 0.6); } + +gridview > child { padding: 3px; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +gridview > child { outline: 0 solid transparent; outline-offset: 4px; } + +gridview > child:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +gridview > child:selected { outline-color: rgba(255, 255, 255, 0.6); } + +gridview > child box { border-spacing: 8px; margin: 12px; } + +coverflow cover { color: white; background-color: #2d2d2d; border: 1px solid black; } + +label { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +label { outline: 0 solid transparent; outline-offset: 4px; } + +label:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +label > selection { background-color: #0f3b71; color: #ffffff; } + +label:disabled { color: #919191; } + +button label:disabled { color: inherit; } + +label.error { color: #cc0000; } + +label.error:disabled { color: rgba(204, 0, 0, 0.5); } + +.dim-label, .titlebar:not(headerbar) .subtitle, headerbar .subtitle, spinbutton.vertical > text > text > placeholder, spinbutton:not(.vertical) > text > placeholder, entry > text > placeholder, label.separator { opacity: 0.9; text-shadow: none; } + +window.assistant .sidebar { padding: 5px; border-top: 1px solid #686868; } + +window.assistant.csd .sidebar { border-top-style: none; } + +window.assistant .sidebar > label { padding: 6px 12px; } + +window.assistant .sidebar > label.highlight { background-color: #161616; border-radius: 5px; } + +window.aboutdialog image.large-icons { -gtk-icon-size: 128px; } + +.osd .scale-popup, .app-notification, .osd popover.background > arrow, .osd popover.background > contents, popover.background.touch-selection > arrow, popover.background.touch-selection > contents, popover.background.magnifier > arrow, popover.background.magnifier > contents, .osd { color: #eeeeec; border: none; background-color: rgba(38, 38, 38, 0.7); background-clip: padding-box; -gtk-icon-shadow: 0 1px black; } + +/********************* Spinner Animation * */ +@keyframes spin { to { transform: rotate(1turn); } } + +spinner { background: none; opacity: 0; -gtk-icon-source: -gtk-icontheme("process-working-symbolic"); } + +spinner:checked { opacity: 1; animation: spin 1s linear infinite; } + +spinner:checked:disabled { opacity: 0.5; } + +/********************** General Typography * */ +.large-title { font-weight: 300; font-size: 24pt; } + +.title-1 { font-weight: 800; font-size: 20pt; } + +.title-2 { font-weight: 800; font-size: 15pt; } + +.title-3 { font-weight: 700; font-size: 15pt; } + +.title-4 { font-weight: 700; font-size: 13pt; } + +.heading { font-weight: 700; font-size: 11pt; } + +.body { font-weight: 400; font-size: 11pt; } + +.caption-heading { font-weight: 700; font-size: 9pt; } + +.caption { font-weight: 400; font-size: 9pt; } + +/**************** Text Entries * */ +spinbutton.vertical > text, spinbutton:not(.vertical), entry { min-height: 32px; padding-left: 8px; padding-right: 8px; border: 1px solid; border-radius: 5px; border-spacing: 6px; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); color: white; border-color: #686868; background-color: #2d2d2d; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +spinbutton.vertical > text, spinbutton:not(.vertical), entry { outline: 0 solid transparent; outline-offset: 4px; } + +spinbutton.vertical > text:focus-within, spinbutton:focus-within:not(.vertical), entry:focus-within { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +spinbutton.vertical > text > image.left, spinbutton:not(.vertical) > image.left, entry > image.left { margin-right: 6px; } + +spinbutton.vertical > text > image.right, spinbutton:not(.vertical) > image.right, entry > image.right { margin-left: 6px; } + +spinbutton.vertical > text > text > block-cursor, spinbutton:not(.vertical) > text > block-cursor, entry > text > block-cursor { color: #2d2d2d; background-color: white; } + +spinbutton.vertical > text.flat, spinbutton.flat:not(.vertical), entry.flat:focus-within, entry.flat:backdrop, entry.flat:disabled, entry.flat { min-height: 0; padding: 2px; background-color: transparent; border-color: transparent; border-radius: 0; } + +spinbutton.vertical > text:focus-within > placeholder, spinbutton:focus-within:not(.vertical) > placeholder, entry:focus-within > placeholder { opacity: 0; /* We hide placeholders on focus */ } + +spinbutton.vertical > text:disabled, spinbutton:disabled:not(.vertical), entry:disabled { color: #919191; border-color: #686868; background-color: #2f2f2f; } + +spinbutton.vertical > text.error, spinbutton.error:not(.vertical), entry.error { color: #cc0000; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +spinbutton.vertical > text.error, spinbutton.error:not(.vertical), entry.error { outline: 0 solid transparent; outline-offset: 4px; } + +spinbutton.vertical > text.error:focus-within, spinbutton.error:focus-within:not(.vertical), entry.error:focus-within { outline-color: rgba(204, 0, 0, 0.5); outline-width: 2px; outline-offset: -2px; } + +spinbutton.vertical > text.error > selection, spinbutton.error:not(.vertical) > selection, entry.error > selection { background-color: #cc0000; } + +spinbutton.vertical > text.warning, spinbutton.warning:not(.vertical), entry.warning { color: #f57900; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +spinbutton.vertical > text.warning, spinbutton.warning:not(.vertical), entry.warning { outline: 0 solid transparent; outline-offset: 4px; } + +spinbutton.vertical > text.warning:focus-within, spinbutton.warning:focus-within:not(.vertical), entry.warning:focus-within { outline-color: rgba(245, 121, 0, 0.5); outline-width: 2px; outline-offset: -2px; } + +spinbutton.vertical > text.warning > selection, spinbutton.warning:not(.vertical) > selection, entry.warning > selection { background-color: #f57900; } + +spinbutton.vertical > text > image, spinbutton:not(.vertical) > image, entry > image { color: #cbcbca; } + +spinbutton.vertical > text > image:hover, spinbutton:not(.vertical) > image:hover, entry > image:hover { color: #f3f3f1; } + +spinbutton.vertical > text > image:active, spinbutton:not(.vertical) > image:active, entry > image:active { color: #0f3b71; } + +spinbutton.vertical > text.password image.caps-lock-indicator, spinbutton.password:not(.vertical) image.caps-lock-indicator, entry.password image.caps-lock-indicator { color: #7e7e7d; } + +spinbutton.vertical > text:drop(active), spinbutton:drop(active):not(.vertical), entry:drop(active):focus-within, entry:drop(active) { border-color: #26a269; box-shadow: inset 0 0 0 1px #26a269; } + +.osd spinbutton.vertical > text, .osd spinbutton:not(.vertical), .osd entry { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: rgba(0, 0, 0, 0.5); background-clip: padding-box; box-shadow: none; -gtk-icon-shadow: 0 1px black; } + +.osd spinbutton.vertical > text:focus-within, .osd spinbutton:focus-within:not(.vertical), .osd entry:focus-within { color: white; border-color: #0f3b71; background-color: rgba(0, 0, 0, 0.5); background-clip: padding-box; } + +.osd spinbutton.vertical > text:disabled, .osd spinbutton:disabled:not(.vertical), .osd entry:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: rgba(58, 58, 57, 0.5); background-clip: padding-box; } + +spinbutton.vertical > text > progress, spinbutton:not(.vertical) > progress, entry > progress { margin-bottom: 2px; } + +spinbutton.vertical > text progress > trough > progress, spinbutton:not(.vertical) progress > trough > progress, entry progress > trough > progress { background-color: transparent; background-image: none; border-radius: 0; border-width: 0 0 2px; border-color: #0f3b71; border-style: solid; box-shadow: none; } + +spinbutton.vertical.linked:not(.vertical) > text:drop(active) + text, spinbutton.vertical.linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + text, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + spinbutton:not(.vertical), .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + spinbutton:not(.vertical), spinbutton.vertical.linked:not(.vertical) > text:drop(active) + button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + menubutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + menubutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + dropdown > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + dropdown > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + colorbutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + colorbutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + fontbutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + fontbutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + filechooserbutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + filechooserbutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + combobox > box > button.combo, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + combobox > box > button.combo, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + entry, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + entry, .linked:not(.vertical) > entry:drop(active) + button, .linked:not(.vertical) > entry:drop(active) + menubutton > button, .linked:not(.vertical) > entry:drop(active) + dropdown > button, .linked:not(.vertical) > entry:drop(active) + colorbutton > button, .linked:not(.vertical) > entry:drop(active) + fontbutton > button, .linked:not(.vertical) > entry:drop(active) + filechooserbutton > button, .linked:not(.vertical) > entry:drop(active) + combobox > box > button.combo, spinbutton.vertical.linked:not(.vertical) > entry:drop(active) + text, .linked:not(.vertical) > entry:drop(active) + spinbutton:not(.vertical), .linked:not(.vertical) > entry:drop(active) + entry { border-left-color: #26a269; } + +spinbutton.vertical.linked > text:not(:disabled) + entry:not(:disabled), .linked.vertical > spinbutton:not(:disabled):not(.vertical) + entry:not(:disabled), spinbutton.vertical.linked > text:not(:disabled) + text:not(:disabled), spinbutton.vertical.linked > spinbutton:not(:disabled):not(.vertical) + text:not(:disabled), spinbutton.vertical.linked > text:not(:disabled) + spinbutton:not(:disabled):not(.vertical), .linked.vertical > spinbutton:not(:disabled):not(.vertical) + spinbutton:not(:disabled):not(.vertical), .linked.vertical > entry:not(:disabled) + entry:not(:disabled), spinbutton.vertical.linked > entry:not(:disabled) + text:not(:disabled), .linked.vertical > entry:not(:disabled) + spinbutton:not(:disabled):not(.vertical) { border-top-color: #3f3f3f; } + +spinbutton.vertical.linked > text:disabled + text:disabled, spinbutton.vertical.linked > spinbutton:disabled:not(.vertical) + text:disabled, spinbutton.vertical.linked > text:disabled + spinbutton:disabled:not(.vertical), .linked.vertical > spinbutton:disabled:not(.vertical) + spinbutton:disabled:not(.vertical), spinbutton.vertical.linked > text:disabled + entry:disabled, .linked.vertical > spinbutton:disabled:not(.vertical) + entry:disabled, spinbutton.vertical.linked > entry:disabled + text:disabled, .linked.vertical > entry:disabled + spinbutton:disabled:not(.vertical), .linked.vertical > entry:disabled + entry:disabled { border-top-color: #3f3f3f; } + +spinbutton.vertical.linked > text + text:drop(active):not(:only-child), spinbutton.vertical.linked > spinbutton:not(.vertical) + text:drop(active):not(:only-child), spinbutton.vertical.linked > text + spinbutton:drop(active):not(:only-child):not(.vertical), .linked.vertical > spinbutton:not(.vertical) + spinbutton:drop(active):not(:only-child):not(.vertical), spinbutton.vertical.linked > text + entry:drop(active):not(:only-child), .linked.vertical > spinbutton:not(.vertical) + entry:drop(active):not(:only-child), spinbutton.vertical.linked > entry + text:drop(active):not(:only-child), .linked.vertical > entry + spinbutton:drop(active):not(:only-child):not(.vertical), .linked.vertical > entry + entry:drop(active):not(:only-child) { border-top-color: #26a269; } + +spinbutton.vertical.linked > text:drop(active):not(:only-child) + text, spinbutton.vertical.linked > spinbutton:drop(active):not(:only-child):not(.vertical) + text, spinbutton.vertical.linked > text:drop(active):not(:only-child) + spinbutton:not(.vertical), .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + spinbutton:not(.vertical), spinbutton.vertical.linked > text:drop(active):not(:only-child) + entry, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + entry, spinbutton.vertical.linked > text:drop(active):not(:only-child) + button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + menubutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + menubutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + dropdown > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + dropdown > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + colorbutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + colorbutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + fontbutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + fontbutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + filechooserbutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + filechooserbutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + combobox > box > button.combo, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + combobox > box > button.combo, spinbutton.vertical.linked > entry:drop(active):not(:only-child) + text, .linked.vertical > entry:drop(active):not(:only-child) + spinbutton:not(.vertical), .linked.vertical > entry:drop(active):not(:only-child) + entry, .linked.vertical > entry:drop(active):not(:only-child) + button, .linked.vertical > entry:drop(active):not(:only-child) + menubutton > button, .linked.vertical > entry:drop(active):not(:only-child) + dropdown > button, .linked.vertical > entry:drop(active):not(:only-child) + colorbutton > button, .linked.vertical > entry:drop(active):not(:only-child) + fontbutton > button, .linked.vertical > entry:drop(active):not(:only-child) + filechooserbutton > button, .linked.vertical > entry:drop(active):not(:only-child) + combobox > box > button.combo { border-top-color: #26a269; } + +spinbutton.vertical > text.error, spinbutton.error:not(.vertical), entry.error { color: #cc0000; } + +treeview entry:focus-within:dir(rtl), treeview entry:focus-within:dir(ltr) { background-color: #2d2d2d; transition-property: color, background; } + +treeview entry.flat, treeview entry { border-radius: 0; background-image: none; background-color: #2d2d2d; } + +treeview entry.flat:focus-within, treeview entry:focus-within { border-color: #0f3b71; } + +/******************* Editable Labels * */ +editablelabel > stack > text { color: white; border-color: #686868; background-color: #2d2d2d; } + +/*********** Buttons * */ +@keyframes needs_attention { from { background-image: radial-gradient(farthest-side, #185fb4 0%, rgba(24, 95, 180, 0) 0%); } + to { background-image: radial-gradient(farthest-side, #185fb4 95%, rgba(24, 95, 180, 0)); } } + +notebook > header > tabs > arrow, windowcontrols button, button { min-height: 24px; min-width: 16px; padding: 4px 9px; border: 1px solid; border-radius: 5px; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); color: #f3f3f1; outline-color: rgba(255, 255, 255, 0.6); border-color: #686868; background-image: linear-gradient(to top, #323232 2px, #353535); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +notebook > header > tabs > arrow, windowcontrols button, button { outline: 0 solid transparent; outline-offset: 4px; } + +notebook > header > tabs > arrow:focus:focus-visible, button:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +notebook > header > tabs > arrow:hover, button:hover { color: #f3f3f1; border-color: #686868; background-image: linear-gradient(to top, #2b2b2b 20%, #2d2d2d 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); -gtk-icon-filter: brightness(1.2); } + +notebook > header > tabs > arrow.keyboard-activating, notebook > header > tabs > arrow:active, notebook > header > tabs > arrow:checked, button.keyboard-activating, button:active, button:checked { color: #f3f3f1; border-color: #686868; background-image: image(#1e1e1e); box-shadow: none; transition-duration: 50ms; } + +notebook > header > tabs > arrow:checked:hover, button:checked:hover { color: #f3f3f1; border-color: #686868; background-image: image(#161616); box-shadow: none; } + +notebook > header > tabs > arrow:checked:active, button:checked:active { color: #f3f3f1; border-color: #686868; background-image: image(#111111); box-shadow: none; } + +notebook > header > tabs > arrow:backdrop, button.flat:backdrop, button:backdrop { color: #919190; border-color: #202020; background-image: image(#353535); box-shadow: none; transition: 200ms ease-out; } + +notebook > header > tabs > arrow:backdrop:not(:disabled), button.flat:backdrop:not(:disabled), button:backdrop:not(:disabled) { -gtk-icon-filter: none; } + +notebook > header > tabs > arrow:backdrop:active, notebook > header > tabs > arrow:backdrop:checked, button.flat:backdrop:active, button.flat:backdrop:checked, button:backdrop:active, button:backdrop:checked { color: #919190; border-color: #202020; background-image: image(#2a2a2a); box-shadow: none; } + +notebook > header > tabs > arrow:backdrop:disabled, button.flat:backdrop:disabled, button:backdrop:disabled { color: #5b5b5b; border-color: #202020; background-image: image(#2f2f2f); box-shadow: none; } + +notebook > header > tabs > arrow:backdrop:disabled:active, notebook > header > tabs > arrow:backdrop:disabled:checked, button.flat:backdrop:disabled:active, button.flat:backdrop:disabled:checked, button:backdrop:disabled:active, button:backdrop:disabled:checked { color: #5b5b5b; border-color: #202020; background-image: image(#2a2a2a); box-shadow: none; } + +notebook > header > tabs > arrow:disabled, button:disabled { color: #919191; border-color: #5d5d5d; background-image: image(#2f2f2f); -gtk-icon-filter: opacity(0.5); } + +notebook > header > tabs > arrow:disabled:active, notebook > header > tabs > arrow:disabled:checked, button:disabled:active, button:disabled:checked { color: #919191; border-color: #5d5d5d; background-image: image(#252525); box-shadow: none; } + - button.sidebar-button, notebook > header > tabs > arrow, windowcontrols button, notebook > header > tabs > arrow.flat, button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; transition: none; } ++button.sidebar-button, notebook > header > tabs > arrow, windowcontrols button, .toolbar button, notebook > header > tabs > arrow.flat, button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; transition: none; } + - button.sidebar-button:hover, notebook > header > tabs > arrow:hover, windowcontrols button:hover, button.flat:hover { border-color: transparent; background-image: none; box-shadow: none; background-color: #323232; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-duration: 500ms; } ++button.sidebar-button:hover, notebook > header > tabs > arrow:hover, windowcontrols button:hover, .toolbar button:hover, button.flat:hover { border-color: transparent; background-image: none; box-shadow: none; background-color: #323232; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-duration: 500ms; } + - button.keyboard-activating.sidebar-button, notebook > header > tabs > arrow.keyboard-activating, windowcontrols button.keyboard-activating, button.sidebar-button:active, notebook > header > tabs > arrow:active, windowcontrols button:active, button.sidebar-button:checked, notebook > header > tabs > arrow:checked, windowcontrols button:checked, button.flat.keyboard-activating, button.flat:active, button.flat:checked { border-color: transparent; background-image: none; box-shadow: none; background-color: #282828; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } ++button.keyboard-activating.sidebar-button, notebook > header > tabs > arrow.keyboard-activating, windowcontrols button.keyboard-activating, .toolbar button.keyboard-activating, button.sidebar-button:active, notebook > header > tabs > arrow:active, windowcontrols button:active, .toolbar button:active, button.sidebar-button:checked, notebook > header > tabs > arrow:checked, windowcontrols button:checked, .toolbar button:checked, button.flat.keyboard-activating, button.flat:active, button.flat:checked { border-color: transparent; background-image: none; box-shadow: none; background-color: #282828; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + - button.sidebar-button:backdrop, notebook > header > tabs > arrow:backdrop, windowcontrols button:backdrop, button.sidebar-button:disabled, notebook > header > tabs > arrow:disabled, windowcontrols button:disabled, button.flat:backdrop, button.flat:disabled, button.flat:backdrop:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; } ++button.sidebar-button:backdrop, notebook > header > tabs > arrow:backdrop, windowcontrols button:backdrop, .toolbar button:backdrop, button.sidebar-button:disabled, notebook > header > tabs > arrow:disabled, windowcontrols button:disabled, .toolbar button:disabled, button.flat:backdrop, button.flat:disabled, button.flat:backdrop:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; } + +notebook > header > tabs > arrow.image-button, button.image-button { min-width: 24px; padding-left: 5px; padding-right: 5px; } + +notebook > header > tabs > arrow.text-button, button.text-button { padding-left: 16px; padding-right: 16px; } + +notebook > header > tabs > arrow.text-button.image-button, button.text-button.image-button { padding-left: 8px; padding-right: 8px; } + +notebook > header > tabs > arrow.text-button.image-button label, button.text-button.image-button label { padding-left: 8px; padding-right: 8px; } + +dropdown:drop(active) button.combo, combobox:drop(active) button.combo, notebook > header > tabs > arrow:drop(active), button:drop(active) { color: #26a269; border-color: #26a269; box-shadow: inset 0 0 0 1px #26a269; } + +row:selected button.sidebar-button:not(:active):not(:checked):not(:hover):not(disabled), row:selected button.flat:not(:active):not(:checked):not(:hover):not(disabled) { color: #ffffff; border-color: transparent; } + +row:selected button.sidebar-button:not(:active):not(:checked):not(:hover):not(disabled):backdrop, row:selected button.flat:not(:active):not(:checked):not(:hover):not(disabled):backdrop { color: #919190; } + +button.osd { min-width: 26px; min-height: 32px; color: #eeeeec; border-radius: 5px; color: #eeeeec; outline-color: rgba(255, 255, 255, 0.6); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; border: none; box-shadow: none; } + +button.osd.image-button { min-width: 30px; } + +button.osd.image-button:only-child { margin: 4px; border-radius: 50%; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); } + +button.osd:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(12, 12, 12, 0.7)); background-clip: padding-box; border: none; box-shadow: none; } + +button.osd:active, button.osd:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; border: none; box-shadow: none; } + +.app-notification button, popover.background.touch-selection button, popover.background.magnifier button, .osd button { color: #eeeeec; outline-color: rgba(255, 255, 255, 0.6); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; } + +.app-notification button:hover, popover.background.touch-selection button:hover, popover.background.magnifier button:hover, .osd button:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(12, 12, 12, 0.7)); background-clip: padding-box; } + +.app-notification button:active, popover.background.touch-selection button:active, popover.background.magnifier button:active, .app-notification button:checked, popover.background.touch-selection button:checked, popover.background.magnifier button:checked, .osd button:active:backdrop, .osd button:active, .osd button:checked:backdrop, .osd button:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; } + +.app-notification button:disabled, popover.background.touch-selection button:disabled, popover.background.magnifier button:disabled, .osd button:disabled:backdrop, .osd button:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; } + +.app-notification button.flat, popover.background.touch-selection button.flat, popover.background.magnifier button.flat, .osd button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; box-shadow: none; -gtk-icon-shadow: 0 1px black; } + +.app-notification button.flat:hover, popover.background.touch-selection button.flat:hover, popover.background.magnifier button.flat:hover, .osd button.flat:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(12, 12, 12, 0.7)); background-clip: padding-box; } + +.app-notification button.flat:disabled, popover.background.touch-selection button.flat:disabled, popover.background.magnifier button.flat:disabled, .osd button.flat:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; background-image: none; border-color: transparent; box-shadow: none; } + +.app-notification button.flat:active, popover.background.touch-selection button.flat:active, popover.background.magnifier button.flat:active, .app-notification button.flat:checked, popover.background.touch-selection button.flat:checked, popover.background.magnifier button.flat:checked, .osd button.flat:active, .osd button.flat:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; } + +button.suggested-action { color: white; outline-color: rgba(255, 255, 255, 0.6); border-color: #030c17; background-image: linear-gradient(to top, #0e396c 2px, #0f3b71); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +button.suggested-action { outline: 0 solid transparent; outline-offset: 4px; } + +button.suggested-action:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +button.suggested-action.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #0f3b71; } + +button.suggested-action:hover { color: white; border-color: #06182d; background-image: linear-gradient(to top, #0d325f 20%, #0d3463 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +button.suggested-action:active, button.suggested-action:checked { color: white; border-color: #06182d; background-image: image(#0a2648); box-shadow: none; } + +button.suggested-action.flat:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: rgba(15, 59, 113, 0.8); } + +button.suggested-action:disabled { color: #919191; border-color: #5d5d5d; background-image: image(#2f2f2f); } + +button.suggested-action:disabled:active, button.suggested-action:disabled:checked { color: #9faab8; border-color: #06182d; background-image: image(#0f2b4d); box-shadow: none; } + +.osd button.suggested-action { color: #eeeeec; outline-color: rgba(255, 255, 255, 0.6); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(15, 59, 113, 0.5)); background-clip: padding-box; } + +.osd button.suggested-action:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(15, 59, 113, 0.7)); background-clip: padding-box; } + +.osd button.suggested-action:active:backdrop, .osd button.suggested-action:active, .osd button.suggested-action:checked:backdrop, .osd button.suggested-action:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(#0f3b71); background-clip: padding-box; box-shadow: none; } + +.osd button.suggested-action:disabled:backdrop, .osd button.suggested-action:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; } + +button.destructive-action { color: white; outline-color: rgba(255, 255, 255, 0.6); border-color: #570b0e; background-image: linear-gradient(to top, #ae151c 2px, #b2161d); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +button.destructive-action { outline: 0 solid transparent; outline-offset: 4px; } + +button.destructive-action:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +button.destructive-action.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #b2161d; } + +button.destructive-action:hover { color: white; border-color: #6e0d12; background-image: linear-gradient(to top, #a0131a 20%, #a5141a 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +button.destructive-action:active, button.destructive-action:checked { color: white; border-color: #6e0d12; background-image: image(#8a1116); box-shadow: none; } + +button.destructive-action.flat:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: rgba(178, 22, 29, 0.8); } + +button.destructive-action:disabled { color: #919191; border-color: #5d5d5d; background-image: image(#2f2f2f); } + +button.destructive-action:disabled:active, button.destructive-action:disabled:checked { color: #cea1a3; border-color: #6e0d12; background-image: image(#84151a); box-shadow: none; } + +.osd button.destructive-action { color: #eeeeec; outline-color: rgba(255, 255, 255, 0.6); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(178, 22, 29, 0.5)); background-clip: padding-box; } + +.osd button.destructive-action:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(178, 22, 29, 0.7)); background-clip: padding-box; } + +.osd button.destructive-action:active:backdrop, .osd button.destructive-action:active, .osd button.destructive-action:checked:backdrop, .osd button.destructive-action:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(#b2161d); background-clip: padding-box; box-shadow: none; } + +.osd button.destructive-action:disabled:backdrop, .osd button.destructive-action:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; } + +stackswitcher > button > label { padding: 0 6px; margin: 0 -6px; } + +stackswitcher > button > image { padding: 3px 6px; margin: -3px -6px; } + +button.font separator { background-color: transparent; } + +button.font > box { border-spacing: 6px; } + +button.font > box > box > label { font-weight: bold; } + +menubutton.circular button, button.circular { min-width: 32px; min-height: 32px; padding: 0; border-radius: 9999px; } + +menubutton.circular button label, button.circular label { padding: 0; } + +stacksidebar row.needs-attention > label, stackswitcher > button.needs-attention > label, stackswitcher > button.needs-attention > image { animation: needs_attention 150ms ease-in; background-image: radial-gradient(farthest-side, #185fb4 96%, rgba(24, 95, 180, 0)); background-size: 6px 6px, 6px 6px; background-repeat: no-repeat; background-position: right 3px, right 2px; } + +stacksidebar row.needs-attention > label:backdrop, stackswitcher > button.needs-attention > label:backdrop, stackswitcher > button.needs-attention > image:backdrop { background-size: 6px 6px, 0 0; } + +stacksidebar row.needs-attention > label:dir(rtl), stackswitcher > button.needs-attention > label:dir(rtl), stackswitcher > button.needs-attention > image:dir(rtl) { background-position: left 3px, left 2px; } + +.linked:not(.vertical) > filechooserbutton > combobox:dir(rtl):not(:last-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(rtl):not(:last-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(rtl):not(:last-child) > box > button.combo, .linked:not(.vertical) > filechooserbutton > combobox:dir(ltr):not(:first-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(ltr):not(:first-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(ltr):not(:first-child) > box > button.combo, dropdown.linked button:nth-child(2):dir(ltr), combobox.linked button:nth-child(2):dir(ltr), .linked:not(.vertical) > menubutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > dropdown:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > colorbutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > fontbutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > filechooserbutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > menubutton:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > dropdown:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > colorbutton:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > fontbutton:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > filechooserbutton:dir(ltr):not(:first-child) > button, spinbutton.vertical.linked:not(.vertical) > text:dir(rtl):not(:last-child), .linked:not(.vertical) > spinbutton:dir(rtl):not(:last-child):not(.vertical), .linked:not(.vertical) > entry:dir(rtl):not(:last-child), .linked:not(.vertical) > button:dir(rtl):not(:last-child), spinbutton.vertical.linked:not(.vertical) > text:dir(ltr):not(:first-child), .linked:not(.vertical) > spinbutton:dir(ltr):not(:first-child):not(.vertical), .linked:not(.vertical) > entry:dir(ltr):not(:first-child), .linked:not(.vertical) > button:dir(ltr):not(:first-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; } + +.linked:not(.vertical) > filechooserbutton > combobox:dir(rtl):not(:first-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(rtl):not(:first-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(rtl):not(:first-child) > box > button.combo, .linked:not(.vertical) > filechooserbutton > combobox:dir(ltr):not(:last-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(ltr):not(:last-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(ltr):not(:last-child) > box > button.combo, dropdown.linked button:nth-child(2):dir(rtl), combobox.linked button:nth-child(2):dir(rtl), .linked:not(.vertical) > menubutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > dropdown:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > colorbutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > fontbutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > filechooserbutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > menubutton:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > dropdown:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > colorbutton:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > fontbutton:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > filechooserbutton:dir(ltr):not(:last-child) > button, spinbutton.vertical.linked:not(.vertical) > text:dir(rtl):not(:first-child), .linked:not(.vertical) > spinbutton:dir(rtl):not(:first-child):not(.vertical), .linked:not(.vertical) > entry:dir(rtl):not(:first-child), .linked:not(.vertical) > button:dir(rtl):not(:first-child), spinbutton.vertical.linked:not(.vertical) > text:dir(ltr):not(:last-child), .linked:not(.vertical) > spinbutton:dir(ltr):not(:last-child):not(.vertical), .linked:not(.vertical) > entry:dir(ltr):not(:last-child), .linked:not(.vertical) > button:dir(ltr):not(:last-child) { border-right-style: none; border-top-right-radius: 0; border-bottom-right-radius: 0; } + +.linked.vertical > filechooserbutton > combobox:not(:first-child) > box > button.combo, .linked.vertical > appchooserbutton > combobox:not(:first-child) > box > button.combo, .linked.vertical > combobox:not(:first-child) > box > button.combo, .linked.vertical > menubutton:not(:first-child) > button, .linked.vertical > dropdown:not(:first-child) > button, .linked.vertical > colorbutton:not(:first-child) > button, .linked.vertical > fontbutton:not(:first-child) > button, .linked.vertical > filechooserbutton:not(:first-child) > button, spinbutton.vertical.linked > text:not(:first-child), .linked.vertical > spinbutton:not(:first-child):not(.vertical), .linked.vertical > entry:not(:first-child), .linked.vertical > button:not(:first-child) { border-top-left-radius: 0; border-top-right-radius: 0; } + +.linked.vertical > filechooserbutton > combobox:not(:last-child) > box > button.combo, .linked.vertical > appchooserbutton > combobox:not(:last-child) > box > button.combo, .linked.vertical > combobox:not(:last-child) > box > button.combo, .linked.vertical > menubutton:not(:last-child) > button, .linked.vertical > dropdown:not(:last-child) > button, .linked.vertical > colorbutton:not(:last-child) > button, .linked.vertical > fontbutton:not(:last-child) > button, .linked.vertical > filechooserbutton:not(:last-child) > button, spinbutton.vertical.linked > text:not(:last-child), .linked.vertical > spinbutton:not(:last-child):not(.vertical), .linked.vertical > entry:not(:last-child), .linked.vertical > button:not(:last-child) { border-bottom-style: none; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } + - .scale-popup button:hover, button.link, button.link:hover, button.link:active, button.link:checked, popover.menu box.circular-buttons button.circular.image-button.model, list > row button.image-button:not(.flat), .toolbar button, modelbutton.flat { background-color: transparent; background-image: none; border-color: transparent; box-shadow: inset 0 1px rgba(255, 255, 255, 0), 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; } ++.scale-popup button:hover, button.link, button.link:hover, button.link:active, button.link:checked, popover.menu box.circular-buttons button.circular.image-button.model, list > row button.image-button:not(.flat), modelbutton.flat { background-color: transparent; background-image: none; border-color: transparent; box-shadow: inset 0 1px rgba(255, 255, 255, 0), 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; } + +/* menu buttons */ +modelbutton.flat { min-height: 26px; padding-left: 5px; padding-right: 5px; border-radius: 5px; } + +modelbutton.flat:hover { background-color: #161616; } + +modelbutton.flat:disabled { color: #919191; } + +modelbutton.flat arrow { background: none; min-width: 16px; min-height: 16px; opacity: 0.3; } + +modelbutton.flat arrow:hover { background: none; } + +modelbutton.flat arrow.left { -gtk-icon-source: -gtk-icontheme("go-previous-symbolic"); } + +modelbutton.flat arrow.right { -gtk-icon-source: -gtk-icontheme("go-next-symbolic"); } + +/* oldstyle toolbar buttons */ +.toolbar button { margin: 1px; } + - .toolbar button:hover { color: #f3f3f1; border-color: #686868; background-image: linear-gradient(to top, #2b2b2b 20%, #2d2d2d 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } - - .toolbar button:active { color: #f3f3f1; border-color: #686868; background-image: image(#1e1e1e); box-shadow: none; } - - .toolbar button:disabled { color: #919191; border-color: #5d5d5d; background-image: image(#2f2f2f); } - - .toolbar button:backdrop { color: #919190; border-color: #202020; background-image: image(#353535); box-shadow: none; } - - .toolbar button:backdrop:disabled { color: #5b5b5b; border-color: #202020; background-image: image(#2f2f2f); box-shadow: none; } - +button.color { padding: 4px; } + +button.color > colorswatch:only-child, button.color > colorswatch:only-child > overlay { border-radius: 0; } + +/* list buttons */ +/* tone down as per new designs, see issue #1473 */ +popover.menu box.circular-buttons button.circular.image-button.model, list > row button.image-button:not(.flat) { border: 1px solid rgba(104, 104, 104, 0.5); } + +popover.menu box.circular-buttons button.circular.image-button.model:hover, list > row button.image-button:not(.flat):hover { color: #f3f3f1; border-color: #686868; background-image: linear-gradient(to top, #2b2b2b 20%, #2d2d2d 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +popover.menu box.circular-buttons button.circular.image-button.model:active, popover.menu box.circular-buttons button.circular.image-button.model:checked, list > row button.image-button:not(.flat):active, list > row button.image-button:not(.flat):checked { color: #f3f3f1; border-color: #686868; background-image: image(#1e1e1e); box-shadow: none; } + +popover.menu box.circular-buttons button.suggested-action.circular.image-button.model, list > row button.image-button.suggested-action:not(.flat) { color: white; outline-color: rgba(255, 255, 255, 0.6); border-color: #030c17; background-image: linear-gradient(to top, #0e396c 2px, #0f3b71); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +popover.menu box.circular-buttons button.suggested-action.circular.image-button.model, list > row button.image-button.suggested-action:not(.flat) { outline: 0 solid transparent; outline-offset: 4px; } + +popover.menu box.circular-buttons button.suggested-action.circular.image-button.model:focus:focus-visible, list > row button.image-button.suggested-action:not(.flat):focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +popover.menu box.circular-buttons button.destructive-action.circular.image-button.model, list > row button.image-button.destructive-action:not(.flat) { color: white; outline-color: rgba(255, 255, 255, 0.6); border-color: #570b0e; background-image: linear-gradient(to top, #ae151c 2px, #b2161d); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +popover.menu box.circular-buttons button.destructive-action.circular.image-button.model, list > row button.image-button.destructive-action:not(.flat) { outline: 0 solid transparent; outline-offset: 4px; } + +popover.menu box.circular-buttons button.destructive-action.circular.image-button.model:focus:focus-visible, list > row button.image-button.destructive-action:not(.flat):focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +/********* Links * */ +button.link, link { color: #3584e4; text-decoration: underline; } + +button.link:visited, link:visited { color: #1b6acb; } + +*:selected button.link:visited, *:selected link:visited { color: #a4c4ea; } + +button.link:hover, link:hover { color: #629fea; } + +*:selected button.link:hover, *:selected link:hover { color: #eff5fd; } + +button.link:active, link:active { color: #3584e4; } + +*:selected button.link:active, *:selected link:active { color: #d7e6fa; } + +button.link:disabled, link:disabled { color: rgba(141, 141, 141, 0.8); } + +button.link:selected, *:selected button.link, link:selected, *:selected link { color: #d7e6fa; } + +link { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +link { outline: 0 solid transparent; outline-offset: 4px; } + +link:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +button.link, button.link:hover, button.link:active, button.link:checked { text-shadow: none; } + +button.link > label { text-decoration: underline; } + +/***************** GtkSpinButton * */ +spinbutton { font-feature-settings: "tnum"; } + +spinbutton:not(.vertical) { padding: 0; border-spacing: 0; /* :not here just to bump specificity above that of the list button styling */ } + +.osd spinbutton:not(.vertical) > text, spinbutton:not(.vertical) > text { min-width: 28px; margin: 0; background: none; background-color: transparent; border: none; border-radius: 0; box-shadow: none; padding: 6px; } + +.osd spinbutton:not(.vertical) > text:backdrop:disabled, spinbutton:not(.vertical) > text:backdrop:disabled { background-color: transparent; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat), spinbutton:not(.vertical) > button.image-button.down:not(.flat) { min-height: 16px; margin: 0; padding-bottom: 0; padding-top: 0; color: #dfdfde; background-image: none; border-style: none none none solid; border-color: rgba(104, 104, 104, 0.3); border-radius: 0; box-shadow: none; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl), spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl) { border-style: none solid none none; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):hover, spinbutton:not(.vertical) > button.image-button.down:not(.flat):hover { color: #f3f3f1; background-color: #232323; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):disabled, spinbutton:not(.vertical) > button.image-button.down:not(.flat):disabled { color: rgba(145, 145, 145, 0.3); background-color: transparent; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):active, spinbutton:not(.vertical) > button.image-button.down:not(.flat):active { background-color: rgba(0, 0, 0, 0.1); box-shadow: inset 0 2px 3px -1px rgba(0, 0, 0, 0.2); } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(ltr):last-child, spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(ltr):last-child { border-radius: 0 5px 5px 0; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl):first-child, spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl):first-child { border-radius: 5px 0 0 5px; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat), .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat) { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #eeeeec; border-style: none none none solid; border-color: rgba(0, 0, 0, 0.4); border-radius: 0; box-shadow: none; -gtk-icon-shadow: 0 1px black; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl), .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl) { border-style: none solid none none; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):hover, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):hover { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #eeeeec; border-color: rgba(0, 0, 0, 0.5); background-color: rgba(12, 12, 12, 0.7); -gtk-icon-shadow: 0 1px black; box-shadow: none; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):disabled, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #8a8a89; border-color: rgba(0, 0, 0, 0.5); -gtk-icon-shadow: none; box-shadow: none; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(ltr):last-child, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(ltr):last-child { border-radius: 0 5px 5px 0; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl):first-child, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl):first-child { border-radius: 5px 0 0 5px; } + +spinbutton.vertical:disabled { color: #919191; } + +spinbutton.vertical:drop(active) { border-color: transparent; box-shadow: none; } + +spinbutton.vertical > text { min-height: 32px; min-width: 32px; padding: 0; border-radius: 0; } + +spinbutton.vertical > text > block-cursor { color: #2d2d2d; background-color: white; } + +spinbutton.vertical > button { min-height: 32px; min-width: 32px; padding: 0; } + +spinbutton.vertical > button.up { border-bottom-style: none; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } + +spinbutton.vertical > button.down { border-top-style: none; border-top-left-radius: 0; border-top-right-radius: 0; } + +.osd spinbutton.vertical > button:first-child { color: #eeeeec; outline-color: rgba(255, 255, 255, 0.6); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; } + +.osd spinbutton.vertical > button:first-child:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(12, 12, 12, 0.7)); background-clip: padding-box; } + +.osd spinbutton.vertical > button:first-child:active { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; } + +.osd spinbutton.vertical > button:first-child:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; } + +treeview spinbutton:not(.vertical) { min-height: 0; border-style: none; border-radius: 0; } + +treeview spinbutton:not(.vertical) > text { min-height: 0; padding: 1px 2px; } + +/************** ComboBoxes * */ +dropdown > popover.menu.background > contents { padding: 0; } + +dropdown > button > box { border-spacing: 6px; } + +dropdown > button > box > stack > row.activatable:hover { background: none; box-shadow: none; } + +dropdown arrow, combobox arrow { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); min-height: 16px; min-width: 16px; } + +dropdown > popover.menu > contents modelbutton, combobox > popover.menu > contents modelbutton { padding-left: 9px; padding-right: 9px; } + +dropdown:drop(active), combobox:drop(active) { box-shadow: none; } + +dropdown popover, combobox popover { margin-top: 6px; padding: 0; } + +dropdown popover listview, combobox popover listview { margin: 8px 0; } + +dropdown popover listview > row.activatable, combobox popover listview > row.activatable { padding: 8px; } + +dropdown popover listview > row.activatable:selected, dropdown popover listview > row.activatable:selected:hover, combobox popover listview > row.activatable:selected, combobox popover listview > row.activatable:selected:hover { outline-color: rgba(255, 255, 255, 0.6); color: white; background-color: #161616; box-shadow: none; } + +dropdown popover .dropdown-searchbar, combobox popover .dropdown-searchbar { padding: 6px; border-bottom: 1px solid #686868; } + +/************ Toolbars * */ +searchbar > revealer > box, .toolbar, toolbar { padding: 4px; border-spacing: 4px; background-color: #303030; } + +.osd .toolbar, .osd toolbar { background-color: transparent; } + +.toolbar.osd, toolbar.osd { padding: 13px; border: none; border-radius: 5px; background-color: rgba(38, 38, 38, 0.7); } + +.toolbar.osd.left, .toolbar.osd.right, .toolbar.osd.top, .toolbar.osd.bottom, toolbar.osd.left, toolbar.osd.right, toolbar.osd.top, toolbar.osd.bottom { border-radius: 0; } + +.toolbar.horizontal > separator, toolbar.horizontal > separator { margin: 4px 0; } + +.toolbar.vertical > separator, toolbar.vertical > separator { margin: 0 4px; } + +searchbar > revealer > box { padding: 6px; border-spacing: 6px; border-width: 0 0 1px; } + +searchbar > revealer > box { border-style: solid; border-color: #686868; background-color: #414141; } + +searchbar > revealer > box:backdrop { border-color: #202020; background-color: #2e2e2e; box-shadow: none; transition: 200ms ease-out; } + +/************** GtkInfoBar * */ +infobar > revealer > box { padding: 8px; border-spacing: 12px; } + +infobar.action:hover > revealer > box { background-color: #59544e; } + +infobar.info > revealer > box, infobar.question > revealer > box, infobar.warning > revealer > box, infobar.error > revealer > box { border-bottom: 1px solid #757575; background-color: #5f5a53; } + +infobar .close, searchbar .close { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; min-width: 16px; min-height: 16px; padding: 4px; border-radius: 50%; } + +infobar .close:hover, searchbar .close:hover { color: #f3f3f1; border-color: #686868; background-image: linear-gradient(to top, #2b2b2b 20%, #2d2d2d 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +/***************** Title buttons * */ +windowcontrols { border-spacing: 6px; } + +windowcontrols.start:not(.empty):dir(ltr), windowcontrols.end:not(.empty):dir(rtl) { margin-right: 7px; } + +windowcontrols.start:not(.empty):dir(rtl), windowcontrols.end:not(.empty):dir(ltr) { margin-left: 7px; } + +windowcontrols button { border-radius: 9999px; padding: 6px; margin: 0 2px; min-width: 0; min-height: 0; } + +windowcontrols button:hover { border-color: transparent; background-image: none; box-shadow: none; background-color: #1b1b1b; } + +windowcontrols button:active, windowcontrols button:checked { border-color: transparent; background-image: none; box-shadow: none; background-color: #070707; } + +/*************** Header bars * */ +.titlebar:not(headerbar), headerbar { padding: 0 6px; min-height: 46px; border-width: 0 0 1px; border-style: solid; border-color: #4e4e4e; border-radius: 0; background: #161616 linear-gradient(to top, #202020, #262626); /* Darken switchbuttons for headerbars. issue #1588 */ } + +.titlebar:backdrop:not(headerbar), headerbar:backdrop { border-color: #202020; background-color: #303030; background-image: none; transition: 200ms ease-out; } + +.titlebar:not(headerbar) .title, headerbar .title { padding-left: 12px; padding-right: 12px; font-weight: bold; } + +.titlebar:not(headerbar) .subtitle, headerbar .subtitle { font-size: smaller; padding-left: 12px; padding-right: 12px; } + +.titlebar:not(headerbar) stackswitcher > button:checked, .titlebar:not(headerbar) button.toggle:checked, headerbar stackswitcher > button:checked, headerbar button.toggle:checked { background: image(#191919); border-color: #606060; border-top-color: #535353; } + +.titlebar:not(headerbar) stackswitcher > button:checked:backdrop, .titlebar:not(headerbar) button.toggle:checked:backdrop, headerbar stackswitcher > button:checked:backdrop, headerbar button.toggle:checked:backdrop { color: #919190; border-color: #202020; background-image: image(#2a2a2a); box-shadow: none; } + +.tiled .titlebar:not(headerbar), .tiled-top .titlebar:not(headerbar), .tiled-left .titlebar:not(headerbar), .tiled-right .titlebar:not(headerbar), .tiled-bottom .titlebar:not(headerbar), .maximized .titlebar:not(headerbar), .fullscreen .titlebar:not(headerbar), .tiled headerbar, .tiled-top headerbar, .tiled-left headerbar, .tiled-right headerbar, .tiled-bottom headerbar, .maximized headerbar, .fullscreen headerbar { border-radius: 0; } + +.default-decoration.titlebar:not(headerbar), headerbar.default-decoration { min-height: 28px; padding: 4px; } + +.default-decoration.titlebar:not(headerbar) windowcontrols button, .default-decoration.titlebar:not(headerbar) windowcontrols menubutton, headerbar.default-decoration windowcontrols button, headerbar.default-decoration windowcontrols menubutton { min-height: 26px; min-width: 26px; margin: 0; padding: 0; } + +.default-decoration.titlebar:not(headerbar) windowcontrols menubutton button, headerbar.default-decoration windowcontrols menubutton button { min-height: 20px; min-width: 20px; margin: 0; padding: 4px; } + +.solid-csd .titlebar:dir(rtl):not(headerbar), .solid-csd .titlebar:dir(ltr):not(headerbar), .solid-csd headerbar:backdrop:dir(rtl), .solid-csd headerbar:backdrop:dir(ltr), .solid-csd headerbar:dir(rtl), .solid-csd headerbar:dir(ltr) { margin-left: -1px; margin-right: -1px; margin-top: -1px; border-radius: 0; box-shadow: none; } + +headerbar > windowhandle > box, headerbar > windowhandle > box > box.start, headerbar > windowhandle > box > box.end { border-spacing: 6px; } + +headerbar entry, headerbar spinbutton, headerbar separator:not(.sidebar), headerbar button, headerbar menubutton { margin-top: 6px; margin-bottom: 6px; } + +headerbar menubutton > button { margin-top: 0px; margin-bottom: 0px; } + +headerbar switch { margin-top: 10px; margin-bottom: 10px; } + +window.csd > .titlebar:not(headerbar) { padding: 0; background-color: transparent; background-image: none; border-style: none; border-color: transparent; } + +.titlebar:not(headerbar) separator { background-color: #686868; } + +window.devel headerbar.titlebar { background: #303030 cross-fade(10% -gtk-icontheme("system-run-symbolic"), image(transparent)) 90% 0/256px 256px no-repeat, linear-gradient(to right, transparent 65%, rgba(15, 59, 113, 0.1)), linear-gradient(to top, #1e1e1e 3px, #232323); } + +window.devel headerbar.titlebar:backdrop { background: #303030 cross-fade(10% -gtk-icontheme("system-run-symbolic"), image(transparent)) 90% 0/256px 256px no-repeat, image(#303030); /* background-color would flash */ } + +/************ Pathbars * */ +pathbar > button.text-button, pathbar > button.image-button, pathbar > button { padding-left: 4px; padding-right: 4px; } + +pathbar > button.text-button.image-button label { padding-left: 0; padding-right: 0; } + +pathbar > button.text-button.image-button label:last-child, pathbar > button label:last-child { padding-right: 8px; } + +pathbar > button.text-button.image-button label:first-child, pathbar > button label:first-child { padding-left: 8px; } + +pathbar > button image { padding-left: 4px; padding-right: 4px; } + +pathbar > button.slider-button { padding-left: 0; padding-right: 0; } + +/************** Tree Views * */ +columnview.view, treeview.view { border-left-color: #555554; border-top-color: #555554; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +columnview.view, treeview.view { outline: 0 solid transparent; outline-offset: 4px; } + +columnview.view:focus:focus-visible, treeview.view:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +columnview.view:selected:focus, columnview.view:selected, treeview.view:selected:focus, treeview.view:selected { border-radius: 0; outline-color: rgba(255, 255, 255, 0.6); } + +columnview.view:disabled, treeview.view:disabled { color: #919191; } + +columnview.view:disabled:selected, treeview.view:disabled:selected { color: #6f8aaa; } + +columnview.view:disabled:selected:backdrop, treeview.view:disabled:selected:backdrop { color: #4b6a8f; } + +columnview.view.separator, treeview.view.separator { min-height: 2px; color: #555554; } + +columnview.view:backdrop, treeview.view:backdrop { border-left-color: #414141; border-top: #414141; } + +columnview.view:drop(active), treeview.view:drop(active) { box-shadow: none; } + +columnview.view > dndtarget:drop(active), treeview.view > dndtarget:drop(active) { border-style: solid none; border-width: 1px; border-color: black; } + +columnview.view > dndtarget.after:drop(active), treeview.view > dndtarget.after:drop(active) { border-top-style: none; } + +columnview.view > dndtarget.before:drop(active), treeview.view > dndtarget.before:drop(active) { border-bottom-style: none; } + +columnview.view.expander, treeview.view.expander { min-width: 16px; min-height: 16px; -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); color: silver; } + +columnview.view.expander:dir(rtl), treeview.view.expander:dir(rtl) { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl"); } + +columnview.view.expander:hover, treeview.view.expander:hover { color: white; } + +columnview.view.expander:selected, treeview.view.expander:selected { color: #b7c4d4; } + +columnview.view.expander:selected:hover, treeview.view.expander:selected:hover { color: #ffffff; } + +columnview.view.expander:checked, treeview.view.expander:checked { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +columnview.view.progressbar, treeview.view.progressbar { background-color: #0f3b71; background-image: image(#0f3b71); box-shadow: none; } + +columnview.view.progressbar:selected:focus, columnview.view.progressbar:selected, treeview.view.progressbar:selected:focus, treeview.view.progressbar:selected { box-shadow: inset 0 1px rgba(255, 255, 255, 0.05); background-image: image(#2d2d2d); } + +columnview.view.progressbar:selected:focus:backdrop, columnview.view.progressbar:selected:backdrop, treeview.view.progressbar:selected:focus:backdrop, treeview.view.progressbar:selected:backdrop { background-color: #303030; } + +columnview.view.trough, treeview.view.trough { background-color: rgba(243, 243, 241, 0.1); } + +columnview.view.trough:selected:focus, columnview.view.trough:selected, treeview.view.trough:selected:focus, treeview.view.trough:selected { background-color: #092444; } + +columnview.view > header > button, treeview.view > header > button { color: #90908f; background-color: #2d2d2d; font-weight: bold; text-shadow: none; box-shadow: none; } + +columnview.view > header > button:hover, treeview.view > header > button:hover { color: #c1c1c0; box-shadow: none; transition: none; } + +columnview.view > header > button:active, treeview.view > header > button:active { color: #f3f3f1; transition: none; } + +columnview.view > header > button sort-indicator, treeview.view > header > button sort-indicator { min-height: 16px; min-width: 16px; } + +columnview.view > header > button sort-indicator.ascending, treeview.view > header > button sort-indicator.ascending { -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); } + +columnview.view > header > button sort-indicator.descending, treeview.view > header > button sort-indicator.descending { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +columnview.view button.dnd:active, columnview.view button.dnd:selected, columnview.view button.dnd:hover, columnview.view button.dnd, columnview.view header.button.dnd:active, columnview.view header.button.dnd:selected, columnview.view header.button.dnd:hover, columnview.view header.button.dnd, treeview.view button.dnd:active, treeview.view button.dnd:selected, treeview.view button.dnd:hover, treeview.view button.dnd, treeview.view header.button.dnd:active, treeview.view header.button.dnd:selected, treeview.view header.button.dnd:hover, treeview.view header.button.dnd { padding: 0 6px; color: #2d2d2d; background-image: none; background-color: #0f3b71; border-style: none; border-radius: 0; box-shadow: inset 0 0 0 1px #2d2d2d; text-shadow: none; transition: none; } + +columnview.view acceleditor > label, treeview.view acceleditor > label { background-color: #0f3b71; } + +columnview.view > header > button, treeview.view > header > button, columnview.view > header > button:hover, treeview.view > header > button:hover, columnview.view > header > button:active, treeview.view > header > button:active { padding: 0 6px; background-image: none; border-style: none none solid solid; border-color: #555554; border-radius: 0; text-shadow: none; } + +columnview.view > header > button:disabled, treeview.view > header > button:disabled { border-color: #303030; background-image: none; } + +columnview.view > header > button:last-child, treeview.view > header > button:last-child { border-right-style: none; } + +/*************** Popovers * */ +popover.background { background-color: transparent; font: initial; } + +popover.background > arrow, popover.background > contents { background-color: #2d2d2d; background-clip: padding-box; border: 1px solid rgba(0, 0, 0, 0.75); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); } + +popover.background:backdrop { background-color: transparent; } + +popover.background > contents { padding: 8px; border-radius: 9px; } + +popover.background > contents > list, popover.background > contents > .view, popover.background > contents > iconview, popover.background > contents > toolbar { border-style: none; background-color: transparent; } + +popover.background > contents separator { background-color: #575757; margin: 3px; } + +popover.background > contents list separator { margin: 0; } + +.osd popover.background, popover.background.touch-selection, popover.background.magnifier { background-color: transparent; } + +.osd popover.background > arrow, .osd popover.background > contents, popover.background.touch-selection > arrow, popover.background.touch-selection > contents, popover.background.magnifier > arrow, popover.background.magnifier > contents { border: 1px solid rgba(255, 255, 255, 0.1); box-shadow: none; } + +magnifier { background-color: #2d2d2d; } + +/********************** Popover Base Menus * */ +popover.menu { padding: 0; } + +popover.menu box.inline-buttons { padding: 0 12px; } + +popover.menu box.inline-buttons button.image-button.model { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; min-height: 30px; min-width: 30px; padding: 0; border: none; outline: none; transition: none; } + +popover.menu box.inline-buttons button.image-button.model:selected { background: image(#161616); } + +popover.menu box.circular-buttons { padding: 12px 12px 6px; } + +popover.menu box.circular-buttons button.circular.image-button.model { padding: 11px; } + +popover.menu box.circular-buttons button.circular.image-button.model:focus { background-color: #161616; border-color: #161616; } + +popover.menu > arrow, popover.menu.background > contents { background-color: #2d2d2d; padding: 5px; } + +popover.menu.background separator { margin: 6px 0; } + +popover.menu accelerator { color: alpha(currentColor,0.55); } + +popover.menu accelerator:dir(ltr) { margin-left: 12px; } + +popover.menu accelerator:dir(rtl) { margin-right: 12px; } + +popover.menu check, popover.menu radio { transform: scale(0.8); border-width: 1.2px; border-color: transparent; box-shadow: none; background-image: image(transparent); color: white; } + +popover.menu check:hover, popover.menu radio:hover { transform: scale(0.8); border-width: 1.2px; color: white; box-shadow: none; background-image: image(transparent); } + +popover.menu check:active, popover.menu radio:active { transform: scale(0.8); border-width: 1.2px; color: white; box-shadow: none; background-image: image(transparent); } + +popover.menu radio { border-color: #686868; } + +popover.menu radio:active { border-color: rgba(104, 104, 104, 0.5); } + +popover.menu arrow.left, popover.menu radio.left, popover.menu check.left { margin-left: -2px; margin-right: 6px; } + +popover.menu arrow.right, popover.menu radio.right, popover.menu check.right { margin-left: 6px; margin-right: -2px; } + +popover.menu modelbutton { min-height: 30px; min-width: 40px; padding: 0 12px; border-radius: 5px; } + +popover.menu modelbutton:selected { color: white; background-color: #161616; } + +popover.menu modelbutton:selected:active { background-color: #0c0c0c; } + +popover.menu label.title { font-weight: bold; padding: 4px 32px; } + +menubar { padding: 0px; box-shadow: inset 0 -1px rgba(0, 0, 0, 0.1); } + +menubar > item { min-height: 16px; padding: 4px 8px; } + +menubar > item:selected { box-shadow: inset 0 -3px #0f3b71; color: #3584e4; } + +menubar > item:disabled { color: #919191; box-shadow: none; } + +menubar > item popover.menu.background > contents { padding: 5px; } + +menubar > item popover.menu popover.menu { padding: 0 0 4px 0; } + +menubar > item popover.menu.background popover.menu.background > contents { margin: 0; border-radius: 9px; } + +/************* Notebooks * */ +notebook { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +notebook > header > tabs > tab:checked { outline: 0 solid transparent; outline-offset: 4px; } + +notebook:focus:focus-visible > header > tabs > tab:checked { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +notebook > header { padding: 1px; border-color: #686868; border-width: 1px; background-color: #282828; } + +notebook > header > tabs { margin: -1px; } + +notebook > header.top { border-bottom-style: solid; } + +notebook > header.top > tabs { margin-bottom: -2px; } + +notebook > header.top > tabs > tab:hover { box-shadow: inset 0 -4px #686868; } + +notebook > header.top > tabs > tab:checked { box-shadow: inset 0 -4px #0f3b71; } + +notebook > header.bottom { border-top-style: solid; } + +notebook > header.bottom > tabs { margin-top: -2px; } + +notebook > header.bottom > tabs > tab:hover { box-shadow: inset 0 4px #686868; } + +notebook > header.bottom > tabs > tab:checked { box-shadow: inset 0 4px #0f3b71; } + +notebook > header.left { border-right-style: solid; } + +notebook > header.left > tabs { margin-right: -2px; } + +notebook > header.left > tabs > tab:hover { box-shadow: inset -4px 0 #686868; } + +notebook > header.left > tabs > tab:checked { box-shadow: inset -4px 0 #0f3b71; } + +notebook > header.right { border-left-style: solid; } + +notebook > header.right > tabs { margin-left: -2px; } + +notebook > header.right > tabs > tab:hover { box-shadow: inset 4px 0 #686868; } + +notebook > header.right > tabs > tab:checked { box-shadow: inset 4px 0 #0f3b71; } + +notebook > header.top > tabs > arrow { border-top-style: none; } + +notebook > header.bottom > tabs > arrow { border-bottom-style: none; } + +notebook > header.top > tabs > arrow, notebook > header.bottom > tabs > arrow { margin-left: -5px; margin-right: -5px; padding-left: 4px; padding-right: 4px; } + +notebook > header.top > tabs > arrow.down, notebook > header.bottom > tabs > arrow.down { -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); } + +notebook > header.top > tabs > arrow.up, notebook > header.bottom > tabs > arrow.up { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } + +notebook > header.left > tabs > arrow { border-left-style: none; } + +notebook > header.right > tabs > arrow { border-right-style: none; } + +notebook > header.left > tabs > arrow, notebook > header.right > tabs > arrow { margin-top: -5px; margin-bottom: -5px; padding-top: 4px; padding-bottom: 4px; } + +notebook > header.left > tabs > arrow.down, notebook > header.right > tabs > arrow.down { -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); } + +notebook > header.left > tabs > arrow.up, notebook > header.right > tabs > arrow.up { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +notebook > header > tabs > arrow { min-height: 16px; min-width: 16px; border-radius: 0; } + +notebook > header > tabs > arrow:hover:not(:active):not(:backdrop) { background-clip: padding-box; background-image: none; background-color: rgba(255, 255, 255, 0.3); border-color: transparent; box-shadow: none; } + +notebook > header > tabs > arrow:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; } + +notebook > header > tabs > tab { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); min-height: 30px; min-width: 30px; padding: 3px 12px; color: #f3f3f1; font-weight: normal; border-width: 1px; border-color: transparent; } + +notebook > header > tabs > tab:hover { color: #f3f3f1; background-color: #1e1e1e; } + +notebook > header > tabs > tab.reorderable-page:hover { border-color: rgba(104, 104, 104, 0.3); background-color: rgba(48, 48, 48, 0.2); } + +notebook > header > tabs > tab:not(:checked) { outline-color: transparent; } + +notebook > header > tabs > tab:checked { color: #f3f3f1; } + +notebook > header > tabs > tab.reorderable-page:checked { border-color: rgba(104, 104, 104, 0.5); background-color: rgba(48, 48, 48, 0.5); } + +notebook > header > tabs > tab.reorderable-page:checked:hover { background-color: rgba(48, 48, 48, 0.7); } + +notebook > header > tabs > tab button.flat { color: alpha(currentColor,0.3); padding: 0; margin-top: 4px; margin-bottom: 4px; min-width: 20px; min-height: 20px; } + +notebook > header > tabs > tab button.flat:hover { color: currentColor; } + +notebook > header > tabs > tab button.flat:last-child { margin-left: 4px; margin-right: -4px; } + +notebook > header > tabs > tab button.flat:first-child { margin-left: -4px; margin-right: 4px; } + +notebook > header.top > tabs, notebook > header.bottom > tabs { padding-left: 4px; padding-right: 4px; } + +notebook > header.top > tabs:not(:only-child), notebook > header.bottom > tabs:not(:only-child) { margin-left: 3px; margin-right: 3px; } + +notebook > header.top > tabs:not(:only-child):first-child, notebook > header.bottom > tabs:not(:only-child):first-child { margin-left: -1px; } + +notebook > header.top > tabs:not(:only-child):last-child, notebook > header.bottom > tabs:not(:only-child):last-child { margin-right: -1px; } + +notebook > header.top > tabs > tab, notebook > header.bottom > tabs > tab { margin-left: 4px; margin-right: 4px; } + +notebook > header.top > tabs > tab.reorderable-page, notebook > header.bottom > tabs > tab.reorderable-page { border-style: none solid; } + +notebook > header.left > tabs, notebook > header.right > tabs { padding-top: 4px; padding-bottom: 4px; } + +notebook > header.left > tabs:not(:only-child), notebook > header.right > tabs:not(:only-child) { margin-top: 3px; margin-bottom: 3px; } + +notebook > header.left > tabs:not(:only-child):first-child, notebook > header.right > tabs:not(:only-child):first-child { margin-top: -1px; } + +notebook > header.left > tabs:not(:only-child):last-child, notebook > header.right > tabs:not(:only-child):last-child { margin-bottom: -1px; } + +notebook > header.left > tabs > tab, notebook > header.right > tabs > tab { margin-top: 4px; margin-bottom: 4px; } + +notebook > header.left > tabs > tab.reorderable-page, notebook > header.right > tabs > tab.reorderable-page { border-style: solid none; } + +notebook > header.top > tabs > tab { padding-bottom: 4px; } + +notebook > header.bottom > tabs > tab { padding-top: 4px; } + +notebook > stack:not(:only-child) { background-color: #2d2d2d; } + +/************** Scrollbars * */ +scrollbar { background-color: #313131; transition: all 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +scrollbar.top { border-bottom: 1px solid #686868; } + +scrollbar.bottom { border-top: 1px solid #686868; } + +scrollbar.left { border-right: 1px solid #686868; } + +scrollbar.right { border-left: 1px solid #686868; } + +scrollbar > range > trough > slider { min-width: 8px; min-height: 8px; margin: -1px; border: 4px solid transparent; border-radius: 10px; background-clip: padding-box; background-color: #a4a4a3; transition: all 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +scrollbar > range > trough > slider:hover { background-color: #c9c9c7; } + +scrollbar > range > trough > slider:hover:active { background-color: #1b6acb; } + +scrollbar > range > trough > slider:disabled { background-color: transparent; } + +scrollbar > range.fine-tune > trough > slider { transition: none; min-width: 6px; min-height: 6px; } + +scrollbar > range.fine-tune.horizontal > trough > slider { border-width: 5px 4px; } + +scrollbar > range.fine-tune.vertical > trough > slider { border-width: 4px 5px; } + +scrollbar.overlay-indicator:not(.dragging):not(.hovering) { border-color: transparent; opacity: 0.4; background-color: transparent; } + +scrollbar.overlay-indicator:not(.dragging):not(.hovering) > range > trough > slider { margin: 0; min-width: 3px; min-height: 3px; background-color: #f3f3f1; border: 1px solid black; } + +scrollbar.overlay-indicator.horizontal:not(.dragging):not(.hovering) > range > trough > slider { margin: 0 2px; min-width: 40px; } + +scrollbar.overlay-indicator.vertical:not(.dragging):not(.hovering) > range > trough > slider { margin: 2px 0; min-height: 40px; } + +scrollbar.overlay-indicator.dragging, scrollbar.overlay-indicator.hovering { opacity: 0.8; } + +scrollbar.horizontal > range > trough > slider { min-width: 40px; } + +scrollbar.vertical > range > trough > slider { min-height: 40px; } + +treeview ~ scrollbar.vertical { border-top: 1px solid #686868; margin-top: -1px; } + +/********** Switch * */ +switch { font-weight: bold; font-size: smaller; border: 1px solid #686868; border-radius: 14px; color: #f3f3f1; background-color: #282828; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; /* only show i / o for the accessible theme */ } + +switch { outline: 0 solid transparent; outline-offset: 4px; } + +switch:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: 0; } + +headerbar switch { background-color: #141414; } + +switch:checked { color: #ffffff; border-color: #1f76e1; background-color: #15539e; } + +switch:disabled { color: #919191; border-color: #686868; background-color: #2f2f2f; text-shadow: none; } + +switch > slider { color: #f3f3f1; outline-color: rgba(255, 255, 255, 0.6); border-color: #686868; background-image: linear-gradient(to top, #323232 2px, #353535); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); margin: -1px; min-width: 24px; min-height: 24px; border: 1px solid; border-color: #686868; border-radius: 50%; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +switch > image { color: transparent; } + +switch:hover > slider { color: #f3f3f1; border-color: #686868; background-image: linear-gradient(to top, #2b2b2b 20%, #2d2d2d 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +switch:checked > slider { border: 1px solid #1f76e1; } + +switch:disabled > slider { color: #919191; border-color: #5d5d5d; background-image: image(#2f2f2f); } + +row:selected switch { outline-color: rgba(255, 255, 255, 0.6); } + +/************************* Check and Radio items * */ +.view.content-view.check:not(list), iconview.content-view.check:not(list), .content-view .tile check:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #15539e; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:hover:not(list), iconview.content-view.check:hover:not(list), .content-view .tile check:hover:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #15539e; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:active:not(list), iconview.content-view.check:active:not(list), .content-view .tile check:active:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #15539e; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:backdrop:not(list), iconview.content-view.check:backdrop:not(list), .content-view .tile check:backdrop:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #5a5a5a; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:checked:not(list), iconview.content-view.check:checked:not(list), .content-view .tile check:checked:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: #15539e; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +.view.content-view.check:checked:hover:not(list), iconview.content-view.check:checked:hover:not(list), .content-view .tile check:checked:hover:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: #15539e; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +.view.content-view.check:checked:active:not(list), iconview.content-view.check:checked:active:not(list), .content-view .tile check:checked:active:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: #15539e; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +.view.content-view.check:backdrop:checked:not(list), iconview.content-view.check:backdrop:checked:not(list), .content-view .tile check:backdrop:checked:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: rgba(238, 238, 236, 0.8); background-color: #5a5a5a; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +checkbutton { border-spacing: 4px; border-radius: 5px; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +checkbutton { outline: 0 solid transparent; outline-offset: 4px; } + +checkbutton:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +checkbutton.text-button { padding: 4px; } + +check, radio { min-height: 14px; min-width: 14px; border: 1px solid; -gtk-icon-source: none; } + +check, radio { background-clip: padding-box; background-image: linear-gradient(to bottom, #3c3c3c 20%, #303030 90%); border-color: #4e4e4e; box-shadow: 0 1px rgba(0, 0, 0, 0.05); color: #ffffff; } + +check:hover, radio:hover { background-image: linear-gradient(to bottom, #474747 10%, #3a3a3a 90%); } + +check:active, radio:active { box-shadow: inset 0 1px black; background-image: image(#232323); } + +check:disabled, radio:disabled { box-shadow: none; color: rgba(255, 255, 255, 0.7); } + +check:checked, radio:checked { background-clip: border-box; background-image: linear-gradient(to bottom, #185fb4 20%, #15539e 90%); border-color: #092444; box-shadow: 0 1px rgba(0, 0, 0, 0.05); color: #ffffff; } + +check:checked:hover, radio:checked:hover { background-image: linear-gradient(to bottom, #1b68c6 10%, #185cb0 90%); } + +check:checked:active, radio:checked:active { box-shadow: inset 0 1px black; background-image: image(#124787); } + +check:checked:disabled, radio:checked:disabled { box-shadow: none; color: rgba(255, 255, 255, 0.7); } + +check:indeterminate, radio:indeterminate { background-clip: border-box; background-image: linear-gradient(to bottom, #185fb4 20%, #15539e 90%); border-color: #092444; box-shadow: 0 1px rgba(0, 0, 0, 0.05); color: #ffffff; } + +check:indeterminate:hover, radio:indeterminate:hover { background-image: linear-gradient(to bottom, #1b68c6 10%, #185cb0 90%); } + +check:indeterminate:active, radio:indeterminate:active { box-shadow: inset 0 1px black; background-image: image(#124787); } + +check:indeterminate:disabled, radio:indeterminate:disabled { box-shadow: none; color: rgba(255, 255, 255, 0.7); } + +.osd check, .osd radio { color: #eeeeec; outline-color: rgba(255, 255, 255, 0.6); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; } + +.osd check:hover, .osd radio:hover { color: #eeeeec; outline-color: rgba(255, 255, 255, 0.6); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; } + +.osd check:active, .osd radio:active { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; } + +.osd check:disabled, .osd radio:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; } + +check { border-radius: 3px; -gtk-icon-size: 14px; } + +check:checked { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets-hc/check-symbolic.symbolic.png")), -gtk-recolor(url("assets-hc/check@2-symbolic.symbolic.png"))); } + +check:indeterminate { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets-hc/dash-symbolic.symbolic.png")), -gtk-recolor(url("assets-hc/dash@2-symbolic.symbolic.png"))); } + +treeview.view radio:selected:focus, treeview.view radio:selected, radio { border-radius: 100%; -gtk-icon-size: 14px; } + +treeview.view radio:checked:selected, radio:checked { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets-hc/bullet-symbolic.symbolic.png")), -gtk-recolor(url("assets-hc/bullet@2-symbolic.symbolic.png"))); } + +treeview.view radio:indeterminate:selected, radio:indeterminate { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets-hc/dash-symbolic.symbolic.png")), -gtk-recolor(url("assets-hc/dash@2-symbolic.symbolic.png"))); } + +treeview.view check:selected:focus, treeview.view check:selected, treeview.view radio:selected:focus, treeview.view radio:selected { color: #ffffff; } + +/************ GtkScale * */ +progressbar > trough, scale > trough > fill, scale > trough { border: 1px solid #282828; border-radius: 3px; background-color: #282828; } + +headerbar progressbar > trough, headerbar scale > trough > fill, headerbar scale > trough { background-color: #141414; } + +progressbar > trough:disabled, scale > trough > fill:disabled, scale > trough:disabled { background-color: #2f2f2f; border-color: #5d5d5d; } + +row:selected progressbar > trough, row:selected scale > trough > fill, row:selected scale > trough { outline-color: rgba(255, 255, 255, 0.6); border-color: black; } + +.osd progressbar > trough, .osd scale > trough > fill, .osd scale > trough { border-color: rgba(0, 0, 0, 0.7); background-color: rgba(0, 0, 0, 0.5); } + +.osd progressbar > trough:disabled, .osd scale > trough > fill:disabled, .osd scale > trough:disabled { background-color: rgba(58, 58, 57, 0.5); } + +progressbar > trough > progress, scale > trough > highlight { border: 1px solid #0f3b71; border-radius: 3px; background-color: #0f3b71; } + +progressbar > trough > progress:disabled, scale > trough > highlight:disabled { background-color: transparent; border-color: transparent; } + +row:selected progressbar > trough > progress, row:selected scale > trough > highlight { border-color: black; } + +.osd progressbar > trough > progress, .osd scale > trough > highlight { border-color: rgba(0, 0, 0, 0.7); } + +.osd progressbar > trough > progress:disabled, .osd scale > trough > highlight:disabled { border-color: transparent; } + +scale { min-height: 10px; min-width: 10px; padding: 12px; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +scale > trough { outline: 0 solid transparent; outline-offset: 16px; } + +scale:focus:focus-visible > trough { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: 10px; } + +scale > trough { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +scale > trough > fill, scale > trough > highlight { margin: -1px; } + +scale > trough > slider { min-height: 18px; min-width: 18px; margin: -9px; } + +scale.fine-tune.horizontal { padding-top: 9px; padding-bottom: 9px; min-height: 16px; } + +scale.fine-tune.vertical { padding-left: 9px; padding-right: 9px; min-width: 16px; } + +scale.fine-tune > trough > slider { margin: -6px; } + +scale.fine-tune > trough > fill, scale.fine-tune > trough > highlight, scale.fine-tune > trough { border-radius: 5px; } + +scale > trough > fill:disabled { border-color: transparent; background-color: transparent; } + +.osd scale > trough > fill { background-color: rgba(91, 91, 90, 0.775); } + +.osd scale > trough > fill:disabled { border-color: transparent; background-color: transparent; } + +scale > trough > slider { color: #f3f3f1; outline-color: rgba(255, 255, 255, 0.6); border-color: #686868; background-image: linear-gradient(to top, #323232 2px, #353535); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); border-width: 1px; border-style: solid; border-radius: 100%; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: background, border, box-shadow; } + +scale > trough > slider:hover { color: #f3f3f1; border-color: #686868; background-image: linear-gradient(to top, #2b2b2b 20%, #2d2d2d 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +scale > trough > slider:active { border-color: black; } + +scale > trough > slider:disabled { color: #919191; border-color: #5d5d5d; background-image: image(#2f2f2f); } + +row:selected scale > trough > slider:disabled, row:selected scale > trough > slider { border-color: black; } + +.osd scale > trough > slider { color: #eeeeec; outline-color: rgba(255, 255, 255, 0.6); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; border-color: rgba(0, 0, 0, 0.7); background-color: #262626; } + +.osd scale > trough > slider:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(12, 12, 12, 0.7)); background-clip: padding-box; background-color: #262626; } + +.osd scale > trough > slider:active { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; background-color: #262626; } + +.osd scale > trough > slider:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; background-color: #262626; } + +scale > value { color: alpha(currentColor,0.55); font-feature-settings: "tnum"; } + +scale.horizontal > marks { color: alpha(currentColor,0.55); } + +scale.horizontal > marks.top { margin-bottom: 6px; } + +scale.horizontal > marks.bottom { margin-top: 6px; } + +scale.horizontal > marks indicator { background-color: currentColor; min-height: 6px; min-width: 1px; } + +scale.horizontal > value.left { margin-right: 9px; } + +scale.horizontal > value.right { margin-left: 9px; } + +scale.horizontal.fine-tune > marks.top { margin-top: 3px; } + +scale.horizontal.fine-tune > marks.bottom { margin-bottom: 3px; } + +scale.horizontal.fine-tune > marks indicator { min-height: 3px; } + +scale.vertical > marks { color: alpha(currentColor,0.55); } + +scale.vertical > marks.top { margin-right: 6px; } + +scale.vertical > marks.bottom { margin-left: 6px; } + +scale.vertical > marks indicator { background-color: currentColor; min-height: 1px; min-width: 6px; } + +scale.vertical > value.top { margin-bottom: 9px; } + +scale.vertical > value.bottom { margin-top: 9px; } + +scale.vertical.fine-tune > marks.top { margin-left: 3px; } + +scale.vertical.fine-tune > marks.bottom { margin-right: 3px; } + +scale.vertical.fine-tune > marks indicator { min-height: 3px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-above-dark.png"), url("assets-hc/slider-horz-scale-has-marks-above-dark@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-above-hover-dark.png"), url("assets-hc/slider-horz-scale-has-marks-above-hover-dark@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-above-active-dark.png"), url("assets-hc/slider-horz-scale-has-marks-above-active-dark@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-above-insensitive-dark.png"), url("assets-hc/slider-horz-scale-has-marks-above-insensitive-dark@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-below-dark.png"), url("assets-hc/slider-horz-scale-has-marks-below-dark@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-below-hover-dark.png"), url("assets-hc/slider-horz-scale-has-marks-below-hover-dark@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-below-active-dark.png"), url("assets-hc/slider-horz-scale-has-marks-below-active-dark@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-below-insensitive-dark.png"), url("assets-hc/slider-horz-scale-has-marks-below-insensitive-dark@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-above-dark.png"), url("assets-hc/slider-vert-scale-has-marks-above-dark@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-above-hover-dark.png"), url("assets-hc/slider-vert-scale-has-marks-above-hover-dark@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-above-active-dark.png"), url("assets-hc/slider-vert-scale-has-marks-above-active-dark@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-above-insensitive-dark.png"), url("assets-hc/slider-vert-scale-has-marks-above-insensitive-dark@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-below-dark.png"), url("assets-hc/slider-vert-scale-has-marks-below-dark@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-below-hover-dark.png"), url("assets-hc/slider-vert-scale-has-marks-below-hover-dark@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-below-active-dark.png"), url("assets-hc/slider-vert-scale-has-marks-below-active-dark@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-below-insensitive-dark.png"), url("assets-hc/slider-vert-scale-has-marks-below-insensitive-dark@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.color { min-height: 0; min-width: 0; } + +scale.color > trough { background-image: image(#686868); background-repeat: no-repeat; } + +scale.color.horizontal { padding: 0 0 15px 0; } + +scale.color.horizontal > trough { padding-bottom: 4px; background-position: 0 -3px; border-top-left-radius: 0; border-top-right-radius: 0; } + +scale.color.horizontal > trough > slider:dir(ltr):hover, scale.color.horizontal > trough > slider:dir(ltr):backdrop, scale.color.horizontal > trough > slider:dir(ltr):disabled, scale.color.horizontal > trough > slider:dir(ltr):backdrop:disabled, scale.color.horizontal > trough > slider:dir(ltr), scale.color.horizontal > trough > slider:dir(rtl):hover, scale.color.horizontal > trough > slider:dir(rtl):backdrop, scale.color.horizontal > trough > slider:dir(rtl):disabled, scale.color.horizontal > trough > slider:dir(rtl):backdrop:disabled, scale.color.horizontal > trough > slider:dir(rtl) { margin-bottom: -15px; margin-top: 6px; } + +scale.color.vertical:dir(ltr) { padding: 0 0 0 15px; } + +scale.color.vertical:dir(ltr) > trough { padding-left: 4px; background-position: 3px 0; border-bottom-right-radius: 0; border-top-right-radius: 0; } + +scale.color.vertical:dir(ltr) > trough > slider:hover, scale.color.vertical:dir(ltr) > trough > slider:backdrop, scale.color.vertical:dir(ltr) > trough > slider:disabled, scale.color.vertical:dir(ltr) > trough > slider:backdrop:disabled, scale.color.vertical:dir(ltr) > trough > slider { margin-left: -15px; margin-right: 6px; } + +scale.color.vertical:dir(rtl) { padding: 0 15px 0 0; } + +scale.color.vertical:dir(rtl) > trough { padding-right: 4px; background-position: -3px 0; border-bottom-left-radius: 0; border-top-left-radius: 0; } + +scale.color.vertical:dir(rtl) > trough > slider:hover, scale.color.vertical:dir(rtl) > trough > slider:backdrop, scale.color.vertical:dir(rtl) > trough > slider:disabled, scale.color.vertical:dir(rtl) > trough > slider:backdrop:disabled, scale.color.vertical:dir(rtl) > trough > slider { margin-right: -15px; margin-left: 6px; } + +scale.color.fine-tune.horizontal:dir(ltr), scale.color.fine-tune.horizontal:dir(rtl) { padding: 0 0 12px 0; } + +scale.color.fine-tune.horizontal:dir(ltr) > trough, scale.color.fine-tune.horizontal:dir(rtl) > trough { padding-bottom: 7px; background-position: 0 -6px; } + +scale.color.fine-tune.horizontal:dir(ltr) > trough > slider, scale.color.fine-tune.horizontal:dir(rtl) > trough > slider { margin-bottom: -15px; margin-top: 6px; } + +scale.color.fine-tune.vertical:dir(ltr) { padding: 0 0 0 12px; } + +scale.color.fine-tune.vertical:dir(ltr) > trough { padding-left: 7px; background-position: 6px 0; } + +scale.color.fine-tune.vertical:dir(ltr) > trough > slider { margin-left: -15px; margin-right: 6px; } + +scale.color.fine-tune.vertical:dir(rtl) { padding: 0 12px 0 0; } + +scale.color.fine-tune.vertical:dir(rtl) > trough { padding-right: 7px; background-position: -6px 0; } + +scale.color.fine-tune.vertical:dir(rtl) > trough > slider { margin-right: -15px; margin-left: 6px; } + +/***************** Progress bars * */ +progressbar { font-size: smaller; color: rgba(243, 243, 241, 0.4); font-feature-settings: "tnum"; } + +progressbar.horizontal > trough { min-width: 150px; } + +progressbar.horizontal > trough, progressbar.horizontal > trough > progress { min-height: 2px; } + +progressbar.vertical > trough { min-height: 80px; } + +progressbar.vertical > trough, progressbar.vertical > trough > progress { min-width: 2px; } + +progressbar.horizontal > trough > progress { margin: 0 -1px; } + +progressbar.vertical > trough > progress { margin: -1px 0; } + +progressbar > trough > progress { /* share most of scales' */ /* override insensitive that is specific to progress */ border-radius: 1.5px; } + +progressbar > trough > progress:disabled { background-color: #919191; border-color: #919191; } + +progressbar > trough > progress.left { border-top-left-radius: 5px; border-bottom-left-radius: 5px; } + +progressbar > trough > progress.right { border-top-right-radius: 5px; border-bottom-right-radius: 5px; } + +progressbar > trough > progress.top { border-top-right-radius: 5px; border-top-left-radius: 5px; } + +progressbar > trough > progress.bottom { border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; } + +progressbar.osd { min-width: 3px; min-height: 3px; background-color: transparent; } + +progressbar.osd > trough { border-style: none; border-radius: 0; background-color: transparent; box-shadow: none; } + +progressbar.osd > trough > progress { border-style: none; border-radius: 0; } + +progressbar > trough.empty > progress { all: unset; } + +/************* Level Bar * */ +levelbar.horizontal trough > block { min-height: 9px; border-radius: 5px; } + +levelbar.horizontal trough > block:dir(rtl) { border-radius: 0 5px 5px 0; } + +levelbar.horizontal trough > block:dir(ltr) { border-radius: 5px 0 0 5px; } + +levelbar.horizontal trough > block.empty, levelbar.horizontal trough > block.full { border-radius: 5px; } + +levelbar.horizontal.discrete trough > block { min-height: 2px; margin: 1px; min-width: 24px; border-radius: 0; } + +levelbar.horizontal.discrete trough > block:first-child { border-radius: 2px 0 0 2px; } + +levelbar.horizontal.discrete trough > block:last-child { border-radius: 0 2px 2px 0; } + +levelbar.vertical trough > block { min-width: 9px; border-radius: 5px; } + +levelbar.vertical.discrete > trough > block { min-width: 2px; margin: 1px 0; min-height: 32px; } + +levelbar > trough { padding: 0; } + +levelbar > trough > block { border: 1px solid; } + +levelbar > trough > block.low { border-color: #f57900; background-color: #f57900; } + +levelbar > trough > block.high, levelbar > trough > block:not(.empty) { border-color: #0f3b71; background-color: #0f3b71; } + +levelbar > trough > block.full { border-color: #26ab62; background-color: #26ab62; } + +levelbar > trough > block.empty { background-color: #232323; border-color: #232323; } + +/**************** Print dialog * */ +window.dialog.print drawing { color: #f3f3f1; background: none; border: none; padding: 0; } + +window.dialog.print drawing paper { background: white; color: #2e3436; border: 1px solid #686868; } + +window.dialog.print .dialog-action-box { margin: 12px; } + +/********** Frames * */ +frame, .frame { border: 1px solid #686868; } + +frame { border-radius: 8px; } + +frame > label { margin: 4px; } + +actionbar > revealer > box { padding: 6px; border-top: 1px solid #686868; } + +actionbar > revealer > box, actionbar > revealer > box > box.start, actionbar > revealer > box > box.end { border-spacing: 6px; } + +scrolledwindow > overshoot.top { background-image: radial-gradient(farthest-side at top, #4e4e4e 85%, rgba(78, 78, 78, 0)), radial-gradient(farthest-side at top, rgba(243, 243, 241, 0.07), rgba(243, 243, 241, 0)); background-size: 100% 3%, 100% 50%; background-repeat: no-repeat; background-position: top; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > overshoot.bottom { background-image: radial-gradient(farthest-side at bottom, #4e4e4e 85%, rgba(78, 78, 78, 0)), radial-gradient(farthest-side at bottom, rgba(243, 243, 241, 0.07), rgba(243, 243, 241, 0)); background-size: 100% 3%, 100% 50%; background-repeat: no-repeat; background-position: bottom; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > overshoot.left { background-image: radial-gradient(farthest-side at left, #4e4e4e 85%, rgba(78, 78, 78, 0)), radial-gradient(farthest-side at left, rgba(243, 243, 241, 0.07), rgba(243, 243, 241, 0)); background-size: 3% 100%, 50% 100%; background-repeat: no-repeat; background-position: left; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > overshoot.right { background-image: radial-gradient(farthest-side at right, #4e4e4e 85%, rgba(78, 78, 78, 0)), radial-gradient(farthest-side at right, rgba(243, 243, 241, 0.07), rgba(243, 243, 241, 0)); background-size: 3% 100%, 50% 100%; background-repeat: no-repeat; background-position: right; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > junction { background: #686868, linear-gradient(to bottom, transparent 1px, #313131 1px), linear-gradient(to right, transparent 1px, #313131 1px); } + +scrolledwindow > junction:dir(rtl) { background: #686868, linear-gradient(to bottom, transparent 1px, #313131 1px), linear-gradient(to left, transparent 1px, #313131 1px); } + +separator { background: #757575; min-width: 1px; min-height: 1px; } + +/********* Lists * */ +listview, list { color: white; background-color: #2d2d2d; border-color: #686868; } + +listview:backdrop, list:backdrop { color: #d6d6d6; background-color: #303030; border-color: #202020; } + +listview > row, list > row { padding: 2px; } + +listview > row.expander, list > row.expander { padding: 0px; } + +listview > row.expander .row-header, list > row.expander .row-header { padding: 2px; } + +listview.horizontal row.separator, listview.separators.horizontal > row:not(.separator), list.horizontal row.separator, list.separators.horizontal > row:not(.separator) { border-left: 1px solid #555554; } + +listview:not(.horizontal) row.separator, listview.separators:not(.horizontal) > row:not(.separator), list:not(.horizontal) row.separator, list.separators:not(.horizontal) > row:not(.separator) { border-bottom: 1px solid #555554; } + +row { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +row { outline: 0 solid transparent; outline-offset: 4px; } + +row:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +row.activatable.has-open-popup, row.activatable:hover { background-color: rgba(243, 243, 241, 0.05); } + +row.activatable:active { box-shadow: inset 0 2px 2px -2px rgba(0, 0, 0, 0.2); } + +row.activatable:selected:active { box-shadow: inset 0 2px 3px -1px rgba(0, 0, 0, 0.5); } + +row.activatable.has-open-popup:selected, row.activatable:selected:hover { background-color: #264e7e; } + +row:selected { outline-color: rgba(255, 255, 255, 0.6); } + +columnview > listview > row { padding: 0; } + +columnview > listview > row > cell { padding: 8px 6px; } + +columnview > listview > row > cell:not(:first-child) { border-left: 1px solid transparent; } + +columnview.column-separators > listview > row > cell { border-left-color: #555554; } + +columnview.data-table > listview > row > cell { padding-top: 2px; padding-bottom: 2px; } + +treeexpander { border-spacing: 4px; } + +/******************************************************** Data Tables * treeview like tables with individual focusable cells * https://gitlab.gnome.org/GNOME/gtk/-/issues/2929 * */ +columnview row:not(:selected) cell editablelabel:not(.editing):focus-within { outline: 2px solid rgba(255, 255, 255, 0.6); } + +columnview row:not(:selected) cell editablelabel.editing:focus-within { outline: 2px solid #0f3b71; } + +columnview row:not(:selected) cell editablelabel.editing text selection { color: #ffffff; background-color: #0f3b71; } + +/******************************************************* Rich Lists * Large list usually containing lots of widgets * https://gitlab.gnome.org/GNOME/gtk/-/issues/3073 * */ +.rich-list { /* rich lists usually containing other widgets than just labels/text */ } + +.rich-list > row { padding: 8px 12px; min-height: 32px; /* should be tall even when only containing a label */ } + +.rich-list > row > box { border-spacing: 12px; } + +/********************* App Notifications * */ +.app-notification { padding: 10px; border-spacing: 10px; border-radius: 0 0 5px 5px; background-color: rgba(38, 38, 38, 0.7); background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.2), transparent 2px); background-clip: padding-box; } + +.app-notification border { border: none; } + +/************* Expanders * */ +expander { min-width: 16px; min-height: 16px; -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } + +expander:dir(rtl) { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl"); } + +expander:disabled { color: #919191; } + +expander:checked { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +expander-widget { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +expander-widget > box > title { outline: 0 solid transparent; outline-offset: 4px; } + +expander-widget:focus:focus-visible > box > title { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +expander-widget > box > title { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); border-radius: 5px; } + +expander-widget > box > title:hover > expander { color: white; } + +.navigation-sidebar:not(decoration):not(window):drop(active):focus, .navigation-sidebar:not(decoration):not(window):drop(active), placessidebar:not(decoration):not(window):drop(active):focus, placessidebar:not(decoration):not(window):drop(active), stackswitcher:not(decoration):not(window):drop(active):focus, stackswitcher:not(decoration):not(window):drop(active), expander-widget:not(decoration):not(window):drop(active):focus, expander-widget:not(decoration):not(window):drop(active) { box-shadow: none; } + +/************ Calendar * */ +calendar { color: white; border: 1px solid #686868; } + +calendar > header { border-bottom: 1px solid #686868; } + +calendar > header > button { border: none; box-shadow: none; background: none; border-radius: 0; } + +calendar > header > button:backdrop { background: none; } + +calendar > grid > label.today { box-shadow: inset 0px -2px #686868; } + +calendar > grid > label.today:selected { box-shadow: none; } + +calendar > grid > label:focus { outline-color: rgba(255, 255, 255, 0.6); outline-offset: -2px; outline-width: 2px; outline-style: solid; } + +calendar > grid > label.day-number { padding: 4px; } + +calendar > grid > label.day-number:selected { border-radius: 3px; } + +calendar > grid > label.day-number.other-month { color: alpha(currentColor,0.3); } + +/*********** Dialogs * */ +window.dialog.message .titlebar { min-height: 20px; background-image: none; background-color: #303030; border-style: none; border-top-left-radius: 7px; border-top-right-radius: 7px; } + +window.dialog.message box.dialog-vbox.vertical { border-spacing: 10px; } + +window.dialog.message label.title { font-weight: 800; font-size: 15pt; } + +window.dialog.message.csd.background { border-bottom-left-radius: 9px; border-bottom-right-radius: 9px; } + +window.dialog.message.csd .dialog-action-area button { padding: 10px 14px; border-radius: 0; border-left-style: solid; border-right-style: none; border-bottom-style: none; } + +window.dialog.message.csd .dialog-action-area button:first-child { border-left-style: none; border-bottom-left-radius: 7px; } + +window.dialog.message.csd .dialog-action-area button:last-child { border-bottom-right-radius: 7px; } + +filechooser .dialog-action-box { border-top: 1px solid #686868; } + +filechooser #pathbarbox { border-bottom: 1px solid #303030; } + +filechooserbutton > button > box { border-spacing: 6px; } + +filechooserbutton:drop(active) { box-shadow: none; border-color: transparent; } + +/*********** Sidebar * */ +.sidebar { background-color: #2e2e2e; } + +.sidebar:not(separator):dir(ltr), .sidebar.left:not(separator), .sidebar.left:not(separator):dir(rtl) { border-right: 1px solid #686868; border-left-style: none; } + +.sidebar:not(separator):dir(rtl), .sidebar.right:not(separator) { border-left: 1px solid #686868; border-right-style: none; } + +.sidebar listview.view, .sidebar list { background-color: transparent; } + +paned .sidebar.left, paned .sidebar.right, paned .sidebar.left:dir(rtl), paned .sidebar:dir(rtl), paned .sidebar:dir(ltr), paned .sidebar { border-style: none; } + +stacksidebar list.separators:not(.horizontal) > row:not(.separator) { border-bottom: none; } + +stacksidebar row { padding: 10px 4px; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +stacksidebar row { outline: 0 solid transparent; outline-offset: 4px; } + +stacksidebar row:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +stacksidebar row > label { padding-left: 6px; padding-right: 6px; } + +stacksidebar row.needs-attention > label { background-size: 6px 6px, 0 0; } + +stacksidebar row:selected { background-color: #161616; border-radius: 5px; color: #f3f3f1; } + +stacksidebar row:selected:hover:dir(ltr), stacksidebar row:selected:hover:dir(rtl) { background-color: #090909; } + +stacksidebar row.activatable:active, stacksidebar row.activatable:selected:active { box-shadow: none; } + +separator.sidebar { background-color: #686868; } + +/********************** Navigation Sidebar * */ +.navigation-sidebar { padding: 5px 0; } + +.navigation-sidebar > separator { margin: 5px; } + +.navigation-sidebar > row { min-height: 36px; padding: 0 8px; border-radius: 5px; margin: 0 5px 2px; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +.navigation-sidebar > row { outline: 0 solid transparent; outline-offset: 4px; } + +.navigation-sidebar > row:focus-visible:focus-within { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: -2px; } + +.navigation-sidebar > row:hover { background-color: #090909; } + +.navigation-sidebar > row:selected { background-color: #161616; color: inherit; } + +.navigation-sidebar > row:selected:hover { background-color: #090909; } + +.navigation-sidebar > row:disabled { color: #919191; } + +/**************** File chooser * */ +row image.sidebar-icon { opacity: 0.7; } + +/* this should be more generic, only using .navigation-sidebar https://gitlab.gnome.org/GNOME/gtk/-/issues/2929 */ +placessidebar .navigation-sidebar > row { padding: 0; } + +placessidebar .navigation-sidebar > row > revealer { padding: 0 14px; } + +placessidebar .navigation-sidebar > row image.sidebar-icon:dir(ltr) { padding-right: 8px; } + +placessidebar .navigation-sidebar > row image.sidebar-icon:dir(rtl) { padding-left: 8px; } + +placessidebar .navigation-sidebar > row label.sidebar-label:dir(ltr) { padding-right: 2px; } + +placessidebar .navigation-sidebar > row label.sidebar-label:dir(rtl) { padding-left: 2px; } + +button.sidebar-button { min-height: 26px; min-width: 26px; margin-top: 3px; margin-bottom: 3px; padding: 0; border-radius: 100%; } + +placessidebar .navigation-sidebar > row:selected:active { box-shadow: none; } + +placessidebar .navigation-sidebar > row.sidebar-placeholder-row { padding: 0 8px; min-height: 2px; background-image: image(#26a269); background-clip: content-box; } + +placessidebar .navigation-sidebar > row.sidebar-new-bookmark-row { color: #0f3b71; } + +placessidebar .navigation-sidebar > row:drop(active):not(:disabled) { color: #26a269; box-shadow: inset 0 1px #26a269, inset 0 -1px #26a269; } + +placessidebar .navigation-sidebar > row:drop(active):not(:disabled):selected { color: #ffffff; background-color: #26a269; } + +placesview .server-list-button > image { transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -gtk-icon-transform: rotate(0turn); } + +placesview .server-list-button:checked > image { transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -gtk-icon-transform: rotate(-0.5turn); } + +placesview > actionbar > revealer > box > box { border-spacing: 6px; } + +/********* Paned * */ +paned > separator { min-width: 1px; min-height: 1px; -gtk-icon-source: none; border-style: none; background-color: transparent; background-image: image(#686868); background-size: 1px 1px; } + +paned > separator:selected { background-image: image(#0f3b71); } + +paned > separator.wide { min-width: 5px; min-height: 5px; background-color: #303030; background-image: image(#686868), image(#686868); background-size: 1px 1px, 1px 1px; } + +paned.horizontal > separator { background-repeat: repeat-y; } + +paned.horizontal > separator:dir(ltr) { margin: 0 -8px 0 0; padding: 0 8px 0 0; background-position: left; } + +paned.horizontal > separator:dir(rtl) { margin: 0 0 0 -8px; padding: 0 0 0 8px; background-position: right; } + +paned.horizontal > separator.wide { margin: 0; padding: 0; background-repeat: repeat-y, repeat-y; background-position: left, right; } + +paned.vertical > separator { margin: 0 0 -8px 0; padding: 0 0 8px 0; background-repeat: repeat-x; background-position: top; } + +paned.vertical > separator.wide { margin: 0; padding: 0; background-repeat: repeat-x, repeat-x; background-position: bottom, top; } + +/************** GtkVideo * */ +video { background: black; } + +video image.osd { min-width: 64px; min-height: 64px; border-radius: 32px; } + +/************ Tooltips * */ +tooltip { padding: 6px 10px; border-radius: 8px; box-shadow: none; } + +tooltip.background { background-color: rgba(0, 0, 0, 0.8); background-clip: padding-box; border: 1px solid rgba(255, 255, 255, 0.1); color: white; } + +tooltip > box { border-spacing: 6px; } + +/***************** Color Chooser * */ +colorswatch { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +colorswatch { outline: 0 solid transparent; outline-offset: 6px; } + +colorswatch:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 4px; outline-offset: -2px; } + +colorswatch:drop(active), colorswatch { border-style: none; } + +colorswatch.top { border-top-left-radius: 5.5px; border-top-right-radius: 5.5px; } + +colorswatch.top > overlay { border-top-left-radius: 5px; border-top-right-radius: 5px; } + +colorswatch.bottom { border-bottom-left-radius: 5.5px; border-bottom-right-radius: 5.5px; } + +colorswatch.bottom > overlay { border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } + +colorswatch.left, colorswatch:first-child:not(.top) { border-top-left-radius: 5.5px; border-bottom-left-radius: 5.5px; } + +colorswatch.left > overlay, colorswatch:first-child:not(.top) > overlay { border-top-left-radius: 5px; border-bottom-left-radius: 5px; } + +colorswatch.right, colorswatch:last-child:not(.bottom) { border-top-right-radius: 5.5px; border-bottom-right-radius: 5.5px; } + +colorswatch.right > overlay, colorswatch:last-child:not(.bottom) > overlay { border-top-right-radius: 5px; border-bottom-right-radius: 5px; } + +colorswatch.dark > overlay { color: white; } + +colorswatch.dark.activatable:hover > overlay { border-color: #686868; } + +colorswatch.light > overlay { color: black; } + +colorswatch.light.activatable:hover > overlay { border-color: #686868; } + +colorswatch:drop(active) { box-shadow: none; } + +colorswatch.light:drop(active) > overlay { border-color: #26a269; box-shadow: inset 0 0 0 2px #686868, inset 0 0 0 1px #26a269; } + +colorswatch.dark:drop(active) > overlay { border-color: #26a269; box-shadow: inset 0 0 0 2px #686868, inset 0 0 0 1px #26a269; } + +colorswatch > overlay { border: 1px solid #686868; } + +colorswatch.activatable:hover > overlay { box-shadow: inset 0 1px rgba(255, 255, 255, 0.4), inset 0 -1px rgba(0, 0, 0, 0.2); } + +colorswatch#add-color-button { border-radius: 5px 0 0 5px; } + +colorswatch#add-color-button:only-child { border-radius: 5px; } + +colorswatch#add-color-button > overlay { color: #f3f3f1; outline-color: rgba(255, 255, 255, 0.6); border-color: #686868; background-image: linear-gradient(to top, #323232 2px, #353535); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +colorswatch#add-color-button.activatable:hover > overlay { color: #f3f3f1; border-color: #686868; background-image: linear-gradient(to top, #2b2b2b 20%, #2d2d2d 90%); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +colorswatch:disabled { opacity: 0.5; } + +colorswatch:disabled > overlay { border-color: rgba(0, 0, 0, 0.6); box-shadow: none; } + +row:selected colorswatch { box-shadow: 0 0 0 2px #ffffff; } + +colorswatch#editor-color-sample { border-radius: 4px; } + +colorswatch#editor-color-sample > overlay { border-radius: 4.5px; } + +plane { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +plane { outline: 0 solid transparent; outline-offset: 6px; } + +plane:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.6); outline-width: 2px; outline-offset: 2px; } + +colorchooser .popover.osd { border-radius: 5px; } + +/******** Misc * */ +.content-view { background-color: #1e1e1e; } + +.content-view:hover { -gtk-icon-filter: brightness(1.2); } + +.content-view .tile { margin: 2px; background-color: black; border-radius: 0; padding: 0; } + +.content-view .tile:active, .content-view .tile:selected { background-color: #0f3b71; } + +.content-view .tile:disabled { background-color: #2f2f2f; } + +.osd .scale-popup button.flat { border-style: none; border-radius: 5px; } + +.scale-popup button:hover { background-color: rgba(243, 243, 241, 0.1); border-radius: 5px; } + +/********************** Window Decorations * */ +window { border-width: 0px; } + +window.csd { box-shadow: 0 3px 9px 1px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(0, 0, 0, 0.75); margin: 0px; border-radius: 8px 8px 0 0; } + +window.csd:backdrop { box-shadow: 0 3px 9px 1px transparent, 0 2px 6px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.75); transition: 200ms ease-out; } + +window.csd.popup { border-radius: 5px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.65); } + +window.csd.dialog.message { border-radius: 8px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.65); } + +window.solid-csd { margin: 0; padding: 4px; border: solid 1px #686868; border-radius: 0; box-shadow: inset 0 0 0 4px #686868, inset 0 0 0 3px #2d2d2d, inset 0 1px rgba(238, 238, 236, 0.07); } + +window.solid-csd:backdrop { box-shadow: inset 0 0 0 4px #686868, inset 0 0 0 3px #353535, inset 0 1px rgba(238, 238, 236, 0.07); } + +window.maximized, window.fullscreen { border-radius: 0; box-shadow: none; } + +window.tiled, window.tiled-top, window.tiled-left, window.tiled-right, window.tiled-bottom { border-radius: 0; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.75), 0 0 0 20px transparent; } + +window:backdrop { box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.75), 0 0 0 20px transparent; } + +window.popup { box-shadow: none; } + +window.ssd { box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.75); } + +tooltip.csd { border-radius: 5px; box-shadow: none; } + +.view:selected:focus, .view:selected, textview > text:selected:focus, textview > text:selected, textview > text > selection:focus, textview > text > selection, iconview:selected:focus, iconview:selected, flowbox > flowboxchild:selected, gridview > child:selected, entry > text > selection, modelbutton.flat:selected, spinbutton:not(.vertical) > text > selection, spinbutton.vertical > text > text > selection, spinbutton.vertical > text > selection, columnview.view:selected:focus, columnview.view:selected, treeview.view:selected:focus, treeview.view:selected, row:selected, calendar > grid > label.day-number:selected { background-color: #0f3b71; } + +label:selected, .view:selected:focus, .view:selected, textview > text:selected:focus, textview > text:selected, textview > text > selection:focus, textview > text > selection, iconview:selected:focus, iconview:selected, flowbox > flowboxchild:selected, gridview > child:selected, entry > text > selection, modelbutton.flat:selected, spinbutton:not(.vertical) > text > selection, spinbutton.vertical > text > text > selection, spinbutton.vertical > text > selection, columnview.view:selected:focus, columnview.view:selected, treeview.view:selected:focus, treeview.view:selected, row:selected, calendar > grid > label.day-number:selected { color: #ffffff; } + +label:disabled > selection, label:disabled:selected, .view:disabled:selected, textview > text:disabled:selected:focus, textview > text:disabled:selected, textview > text > selection:disabled, iconview:disabled:selected:focus, iconview:disabled:selected, flowbox > flowboxchild:disabled:selected, gridview > child:disabled:selected, entry > text > selection:disabled, modelbutton.flat:disabled:selected, spinbutton:not(.vertical) > text > selection:disabled, spinbutton.vertical > text > text > selection:disabled, spinbutton.vertical > text > selection:disabled, columnview.view:disabled:selected, treeview.view:disabled:selected, row:disabled:selected, calendar > grid > label.day-number:disabled:selected { color: #879db8; } + +.monospace { font-family: monospace; } + +/********************** Touch Copy & Paste * */ +cursor-handle { background-color: transparent; background-image: none; box-shadow: none; border-style: none; min-width: 20px; min-height: 24px; padding-left: 20px; padding-right: 20px; padding-top: 24px; padding-bottom: 24px; } + +cursor-handle.top:dir(ltr), cursor-handle.bottom:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/text-select-start-dark.png"), url("assets-hc/text-select-start-dark@2.png")); } + +cursor-handle.bottom:dir(ltr), cursor-handle.top:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/text-select-end-dark.png"), url("assets-hc/text-select-end-dark@2.png")); } + +cursor-handle.insertion-cursor:dir(ltr), cursor-handle.insertion-cursor:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-above-dark.png"), url("assets-hc/slider-horz-scale-has-marks-above-dark@2.png")); } + +cursor-handle.top:hover:dir(ltr), cursor-handle.bottom:hover:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/text-select-start-hover-dark.png"), url("assets-hc/text-select-start-hover-dark@2.png")); } + +cursor-handle.bottom:hover:dir(ltr), cursor-handle.top:hover:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/text-select-end-hover-dark.png"), url("assets-hc/text-select-end-hover-dark@2.png")); } + +cursor-handle.insertion-cursor:hover:dir(ltr), cursor-handle.insertion-cursor:hover:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-above-hover-dark.png"), url("assets-hc/slider-horz-scale-has-marks-above-hover-dark@2.png")); } + +cursor-handle.top:active:dir(ltr), cursor-handle.bottom:active:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/text-select-start-active-dark.png"), url("assets-hc/text-select-start-active-dark@2.png")); } + +cursor-handle.bottom:active:dir(ltr), cursor-handle.top:active:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/text-select-end-active-dark.png"), url("assets-hc/text-select-end-active-dark@2.png")); } + +cursor-handle.insertion-cursor:active:dir(ltr), cursor-handle.insertion-cursor:active:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-above-active-dark.png"), url("assets-hc/slider-horz-scale-has-marks-above-active-dark@2.png")); } + +shortcuts-section { margin: 20px; } + +.shortcuts-search-results { margin: 20px; border-spacing: 24px; } + +shortcut { border-spacing: 6px; } + +shortcut > .keycap { min-width: 20px; min-height: 25px; margin-top: 2px; padding-bottom: 3px; padding-left: 6px; padding-right: 6px; color: #f3f3f1; background-color: #2d2d2d; border: 1px solid; border-color: #686868; border-radius: 5px; box-shadow: inset 0 -3px #505050; font-size: smaller; } + +:not(decoration):not(window):drop(active):focus, :not(decoration):not(window):drop(active) { border-color: #26a269; box-shadow: inset 0 0 0 1px #26a269; caret-color: #26a269; } + +stackswitcher > button.text-button { min-width: 100px; } + +stackswitcher.circular { border-spacing: 12px; } + +stackswitcher.circular > button.circular, stackswitcher.circular > button.text-button.circular { min-width: 32px; min-height: 32px; padding: 0; } + +/************* App Icons * */ +/* Outline for low res icons */ +.lowres-icon { -gtk-icon-shadow: 0 -1px rgba(0, 0, 0, 0.05), 1px 0 rgba(0, 0, 0, 0.1), 0 1px rgba(0, 0, 0, 0.3), -1px 0 rgba(0, 0, 0, 0.1); } + +/* Drapshadow for large icons */ +.icon-dropshadow { -gtk-icon-shadow: 0 1px 12px rgba(0, 0, 0, 0.05), 0 -1px rgba(0, 0, 0, 0.05), 1px 0 rgba(0, 0, 0, 0.1), 0 1px rgba(0, 0, 0, 0.3), -1px 0 rgba(0, 0, 0, 0.1); } + +/********* Emoji * */ +popover.emoji-picker > contents { padding: 0; } + +.emoji-searchbar { padding: 6px; border-spacing: 6px; border-bottom: 1px solid #686868; } + +.emoji-toolbar { padding: 6px; border-spacing: 6px; border-top: 1px solid #686868; } + +button.emoji-section { border-color: transparent; border-width: 3px; border-style: none none solid; border-radius: 0; padding: 3px 0 0; min-width: 32px; min-height: 28px; /* reset props inherited from the button style */ background: none; box-shadow: none; text-shadow: none; } + +button.emoji-section:hover { border-color: rgba(243, 243, 241, 0.1); } + +button.emoji-section:checked { border-color: #0f3b71; } + +popover.emoji-picker emoji { font-size: x-large; padding: 6px; border-radius: 6px; } + +popover.emoji-picker emoji:focus, popover.emoji-picker emoji:hover { background: #0f3b71; } + +emoji-completion-row > box { border-spacing: 10px; padding: 2px 10px; } + +emoji-completion-row:focus, emoji-completion-row:hover { background-color: #0f3b71; color: #ffffff; } + +emoji-completion-row emoji:focus, emoji-completion-row emoji:hover { background-color: #161616; } + +popover.entry-completion > contents { padding: 0; } + +statusbar { padding: 6px 10px 6px 10px; } + +menubutton > button > box { border-spacing: 6px; } + +menubutton arrow { min-height: 16px; min-width: 16px; } + +menubutton arrow.none { -gtk-icon-source: -gtk-icontheme("open-menu-symbolic"); } + +menubutton arrow.down { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +menubutton arrow.up { -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); } + +menubutton arrow.left { -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); } + +menubutton arrow.right { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } diff --cc gtk/theme/Default/Default-hc.css index e965306920,0000000000..f6d8cd92ab mode 100644,000000..100644 --- a/gtk/theme/Default/Default-hc.css +++ b/gtk/theme/Default/Default-hc.css @@@ -1,1869 -1,0 +1,1859 @@@ +/* GTK NAMED COLORS ---------------- use responsibly! */ +/* +widget text/foreground color */ +@define-color theme_fg_color #272c2e; +/* +text color for entries, views and content in general */ +@define-color theme_text_color black; +/* +widget base background color */ +@define-color theme_bg_color #fdfdfc; +/* +text widgets and the like base background color */ +@define-color theme_base_color #ffffff; +/* +base background color of selections */ +@define-color theme_selected_bg_color #1b6acb; +/* +text/foreground color of selections */ +@define-color theme_selected_fg_color #ffffff; +/* +base background color of insensitive widgets */ +@define-color insensitive_bg_color #fefefd; +/* +text foreground color of insensitive widgets */ +@define-color insensitive_fg_color #929495; +/* +insensitive text widgets and the like base background color */ +@define-color insensitive_base_color #ffffff; +/* +widget text/foreground color on backdrop windows */ +@define-color theme_unfocused_fg_color #929595; +/* +text color for entries, views and content in general on backdrop windows */ +@define-color theme_unfocused_text_color black; +/* +widget base background color on backdrop windows */ +@define-color theme_unfocused_bg_color #f6f5f4; +/* +text widgets and the like base background color on backdrop windows */ +@define-color theme_unfocused_base_color #fcfcfc; +/* +base background color of selections on backdrop windows */ +@define-color theme_unfocused_selected_bg_color #1b6acb; +/* +text/foreground color of selections on backdrop windows */ +@define-color theme_unfocused_selected_fg_color #ffffff; +/* +insensitive color on backdrop windows*/ +@define-color unfocused_insensitive_color #d4cfca; +/* +widgets main borders color */ +@define-color borders #877b6e; +/* +widgets main borders color on backdrop windows */ +@define-color unfocused_borders #d5d0cc; +/* +these are pretty self explicative */ +@define-color warning_color #f57900; +@define-color error_color #cc0000; +@define-color success_color #33d17a; +/* +these colors are exported for the window manager and shouldn't be used in applications, +read if you used those and something break with a version upgrade you're on your own... */ +@define-color wm_title shade(#272c2e, 1.8); +@define-color wm_unfocused_title #929595; +@define-color wm_highlight rgba(255, 255, 255, 0.8); +@define-color wm_borders_edge rgba(255, 255, 255, 0.8); +@define-color wm_bg_a shade(#fdfdfc, 1.2); +@define-color wm_bg_b #fdfdfc; +@define-color wm_shadow alpha(black, 0.35); +@define-color wm_border alpha(black, 0.18); +@define-color wm_button_hover_color_a shade(#fdfdfc, 1.3); +@define-color wm_button_hover_color_b #fdfdfc; +@define-color wm_button_active_color_a shade(#fdfdfc, 0.85); +@define-color wm_button_active_color_b shade(#fdfdfc, 0.89); +@define-color wm_button_active_color_c shade(#fdfdfc, 0.9); +/* content view background such as thumbnails view in Photos or Boxes */ +@define-color content_view_bg #ffffff; +/* Very contrasty background for text views (@theme_text_color foreground) */ +@define-color text_view_bg #ffffff; +/*************************** Check and Radio buttons * */ +/*************** Base States * */ +.background { color: #272c2e; background-color: #fdfdfc; } + +.background:backdrop { text-shadow: none; -gtk-icon-shadow: none; } + +dnd { color: #272c2e; } + +.normal-icons { -gtk-icon-size: 16px; } + +.large-icons { -gtk-icon-size: 32px; } + +image:disabled { -gtk-icon-filter: opacity(0.5); } + +.view, iconview, textview > text { color: black; background-color: #ffffff; } + +.view:disabled, iconview:disabled, textview > text:disabled { color: #929495; background-color: #fefefd; } + +.view:selected:focus, iconview:selected:focus, .view:selected, iconview:selected, textview > text:selected:focus, textview > text:selected { border-radius: 3px; } + +textview:drop(active) { caret-color: #2ec27e; } + +textview > border { background-color: #fefefe; } + +iconview { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +iconview { outline: 0 solid transparent; outline-offset: 4px; } + +iconview:focus:focus-visible { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: -2px; } + +iconview:drop(active) { box-shadow: none; } + +iconview > dndtarget:drop(active) { border-style: solid; border-width: 1px; border-color: #124787; } + +rubberband, .content-view > rubberband, columnview.view > rubberband, treeview.view > rubberband, gridview > rubberband, flowbox > rubberband { border: 1px solid #15539e; background-color: rgba(21, 83, 158, 0.2); } + +flowbox > flowboxchild { padding: 3px; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +flowbox > flowboxchild { outline: 0 solid transparent; outline-offset: 4px; } + +flowbox > flowboxchild:focus:focus-visible { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: -2px; } + +flowbox > flowboxchild:selected { outline-color: white; } + +gridview > child { padding: 3px; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +gridview > child { outline: 0 solid transparent; outline-offset: 4px; } + +gridview > child:focus:focus-visible { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: -2px; } + +gridview > child:selected { outline-color: white; } + +gridview > child box { border-spacing: 8px; margin: 12px; } + +coverflow cover { color: black; background-color: #ffffff; border: 1px solid black; } + +label { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +label { outline: 0 solid transparent; outline-offset: 4px; } + +label:focus:focus-visible { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: -2px; } + +label > selection { background-color: #1b6acb; color: #ffffff; } + +label:disabled { color: #929495; } + +button label:disabled { color: inherit; } + +label.error { color: #cc0000; } + +label.error:disabled { color: rgba(204, 0, 0, 0.5); } + +.dim-label, .titlebar:not(headerbar) .subtitle, headerbar .subtitle, spinbutton.vertical > text > text > placeholder, spinbutton:not(.vertical) > text > placeholder, entry > text > placeholder, label.separator { opacity: 0.9; text-shadow: none; } + +window.assistant .sidebar { padding: 5px; border-top: 1px solid #877b6e; } + +window.assistant.csd .sidebar { border-top-style: none; } + +window.assistant .sidebar > label { padding: 6px 12px; } + +window.assistant .sidebar > label.highlight { background-color: #e6e3e0; border-radius: 5px; } + +window.aboutdialog image.large-icons { -gtk-icon-size: 128px; } + +.osd .scale-popup, .app-notification, .osd popover.background > arrow, .osd popover.background > contents, popover.background.touch-selection > arrow, popover.background.touch-selection > contents, popover.background.magnifier > arrow, popover.background.magnifier > contents, .osd { color: #eeeeec; border: none; background-color: rgba(53, 53, 53, 0.7); background-clip: padding-box; -gtk-icon-shadow: 0 1px black; } + +/********************* Spinner Animation * */ +@keyframes spin { to { transform: rotate(1turn); } } + +spinner { background: none; opacity: 0; -gtk-icon-source: -gtk-icontheme("process-working-symbolic"); } + +spinner:checked { opacity: 1; animation: spin 1s linear infinite; } + +spinner:checked:disabled { opacity: 0.5; } + +/********************** General Typography * */ +.large-title { font-weight: 300; font-size: 24pt; } + +.title-1 { font-weight: 800; font-size: 20pt; } + +.title-2 { font-weight: 800; font-size: 15pt; } + +.title-3 { font-weight: 700; font-size: 15pt; } + +.title-4 { font-weight: 700; font-size: 13pt; } + +.heading { font-weight: 700; font-size: 11pt; } + +.body { font-weight: 400; font-size: 11pt; } + +.caption-heading { font-weight: 700; font-size: 9pt; } + +.caption { font-weight: 400; font-size: 9pt; } + +/**************** Text Entries * */ +spinbutton.vertical > text, spinbutton:not(.vertical), entry { min-height: 32px; padding-left: 8px; padding-right: 8px; border: 1px solid; border-radius: 5px; border-spacing: 6px; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); color: black; border-color: #877b6e; background-color: #ffffff; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +spinbutton.vertical > text, spinbutton:not(.vertical), entry { outline: 0 solid transparent; outline-offset: 4px; } + +spinbutton.vertical > text:focus-within, spinbutton:focus-within:not(.vertical), entry:focus-within { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: -2px; } + +spinbutton.vertical > text > image.left, spinbutton:not(.vertical) > image.left, entry > image.left { margin-right: 6px; } + +spinbutton.vertical > text > image.right, spinbutton:not(.vertical) > image.right, entry > image.right { margin-left: 6px; } + +spinbutton.vertical > text > text > block-cursor, spinbutton:not(.vertical) > text > block-cursor, entry > text > block-cursor { color: #ffffff; background-color: black; } + +spinbutton.vertical > text.flat, spinbutton.flat:not(.vertical), entry.flat:focus-within, entry.flat:backdrop, entry.flat:disabled, entry.flat { min-height: 0; padding: 2px; background-color: transparent; border-color: transparent; border-radius: 0; } + +spinbutton.vertical > text:focus-within > placeholder, spinbutton:focus-within:not(.vertical) > placeholder, entry:focus-within > placeholder { opacity: 0; /* We hide placeholders on focus */ } + +spinbutton.vertical > text:disabled, spinbutton:disabled:not(.vertical), entry:disabled { color: #929495; border-color: #877b6e; background-color: #fefefd; } + +spinbutton.vertical > text.error, spinbutton.error:not(.vertical), entry.error { color: #cc0000; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +spinbutton.vertical > text.error, spinbutton.error:not(.vertical), entry.error { outline: 0 solid transparent; outline-offset: 4px; } + +spinbutton.vertical > text.error:focus-within, spinbutton.error:focus-within:not(.vertical), entry.error:focus-within { outline-color: rgba(204, 0, 0, 0.5); outline-width: 2px; outline-offset: -2px; } + +spinbutton.vertical > text.error > selection, spinbutton.error:not(.vertical) > selection, entry.error > selection { background-color: #cc0000; } + +spinbutton.vertical > text.warning, spinbutton.warning:not(.vertical), entry.warning { color: #f57900; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +spinbutton.vertical > text.warning, spinbutton.warning:not(.vertical), entry.warning { outline: 0 solid transparent; outline-offset: 4px; } + +spinbutton.vertical > text.warning:focus-within, spinbutton.warning:focus-within:not(.vertical), entry.warning:focus-within { outline-color: rgba(245, 121, 0, 0.5); outline-width: 2px; outline-offset: -2px; } + +spinbutton.vertical > text.warning > selection, spinbutton.warning:not(.vertical) > selection, entry.warning > selection { background-color: #f57900; } + +spinbutton.vertical > text > image, spinbutton:not(.vertical) > image, entry > image { color: #525658; } + +spinbutton.vertical > text > image:hover, spinbutton:not(.vertical) > image:hover, entry > image:hover { color: #272c2e; } + +spinbutton.vertical > text > image:active, spinbutton:not(.vertical) > image:active, entry > image:active { color: #1b6acb; } + +spinbutton.vertical > text.password image.caps-lock-indicator, spinbutton.password:not(.vertical) image.caps-lock-indicator, entry.password image.caps-lock-indicator { color: #a7aaaa; } + +spinbutton.vertical > text:drop(active), spinbutton:drop(active):not(.vertical), entry:drop(active):focus-within, entry:drop(active) { border-color: #2ec27e; box-shadow: inset 0 0 0 1px #2ec27e; } + +.osd spinbutton.vertical > text, .osd spinbutton:not(.vertical), .osd entry { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: rgba(0, 0, 0, 0.5); background-clip: padding-box; box-shadow: none; -gtk-icon-shadow: 0 1px black; } + +.osd spinbutton.vertical > text:focus-within, .osd spinbutton:focus-within:not(.vertical), .osd entry:focus-within { color: white; border-color: #1b6acb; background-color: rgba(0, 0, 0, 0.5); background-clip: padding-box; } + +.osd spinbutton.vertical > text:disabled, .osd spinbutton:disabled:not(.vertical), .osd entry:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: rgba(71, 71, 71, 0.5); background-clip: padding-box; } + +spinbutton.vertical > text > progress, spinbutton:not(.vertical) > progress, entry > progress { margin-bottom: 2px; } + +spinbutton.vertical > text progress > trough > progress, spinbutton:not(.vertical) progress > trough > progress, entry progress > trough > progress { background-color: transparent; background-image: none; border-radius: 0; border-width: 0 0 2px; border-color: #1b6acb; border-style: solid; box-shadow: none; } + +spinbutton.vertical.linked:not(.vertical) > text:drop(active) + text, spinbutton.vertical.linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + text, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + spinbutton:not(.vertical), .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + spinbutton:not(.vertical), spinbutton.vertical.linked:not(.vertical) > text:drop(active) + button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + menubutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + menubutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + dropdown > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + dropdown > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + colorbutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + colorbutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + fontbutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + fontbutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + filechooserbutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + filechooserbutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + combobox > box > button.combo, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + combobox > box > button.combo, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + entry, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + entry, .linked:not(.vertical) > entry:drop(active) + button, .linked:not(.vertical) > entry:drop(active) + menubutton > button, .linked:not(.vertical) > entry:drop(active) + dropdown > button, .linked:not(.vertical) > entry:drop(active) + colorbutton > button, .linked:not(.vertical) > entry:drop(active) + fontbutton > button, .linked:not(.vertical) > entry:drop(active) + filechooserbutton > button, .linked:not(.vertical) > entry:drop(active) + combobox > box > button.combo, spinbutton.vertical.linked:not(.vertical) > entry:drop(active) + text, .linked:not(.vertical) > entry:drop(active) + spinbutton:not(.vertical), .linked:not(.vertical) > entry:drop(active) + entry { border-left-color: #2ec27e; } + +spinbutton.vertical.linked > text:not(:disabled) + entry:not(:disabled), .linked.vertical > spinbutton:not(:disabled):not(.vertical) + entry:not(:disabled), spinbutton.vertical.linked > text:not(:disabled) + text:not(:disabled), spinbutton.vertical.linked > spinbutton:not(:disabled):not(.vertical) + text:not(:disabled), spinbutton.vertical.linked > text:not(:disabled) + spinbutton:not(:disabled):not(.vertical), .linked.vertical > spinbutton:not(:disabled):not(.vertical) + spinbutton:not(:disabled):not(.vertical), .linked.vertical > entry:not(:disabled) + entry:not(:disabled), spinbutton.vertical.linked > entry:not(:disabled) + text:not(:disabled), .linked.vertical > entry:not(:disabled) + spinbutton:not(:disabled):not(.vertical) { border-top-color: #dbd7d4; } + +spinbutton.vertical.linked > text:disabled + text:disabled, spinbutton.vertical.linked > spinbutton:disabled:not(.vertical) + text:disabled, spinbutton.vertical.linked > text:disabled + spinbutton:disabled:not(.vertical), .linked.vertical > spinbutton:disabled:not(.vertical) + spinbutton:disabled:not(.vertical), spinbutton.vertical.linked > text:disabled + entry:disabled, .linked.vertical > spinbutton:disabled:not(.vertical) + entry:disabled, spinbutton.vertical.linked > entry:disabled + text:disabled, .linked.vertical > entry:disabled + spinbutton:disabled:not(.vertical), .linked.vertical > entry:disabled + entry:disabled { border-top-color: #dbd7d4; } + +spinbutton.vertical.linked > text + text:drop(active):not(:only-child), spinbutton.vertical.linked > spinbutton:not(.vertical) + text:drop(active):not(:only-child), spinbutton.vertical.linked > text + spinbutton:drop(active):not(:only-child):not(.vertical), .linked.vertical > spinbutton:not(.vertical) + spinbutton:drop(active):not(:only-child):not(.vertical), spinbutton.vertical.linked > text + entry:drop(active):not(:only-child), .linked.vertical > spinbutton:not(.vertical) + entry:drop(active):not(:only-child), spinbutton.vertical.linked > entry + text:drop(active):not(:only-child), .linked.vertical > entry + spinbutton:drop(active):not(:only-child):not(.vertical), .linked.vertical > entry + entry:drop(active):not(:only-child) { border-top-color: #2ec27e; } + +spinbutton.vertical.linked > text:drop(active):not(:only-child) + text, spinbutton.vertical.linked > spinbutton:drop(active):not(:only-child):not(.vertical) + text, spinbutton.vertical.linked > text:drop(active):not(:only-child) + spinbutton:not(.vertical), .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + spinbutton:not(.vertical), spinbutton.vertical.linked > text:drop(active):not(:only-child) + entry, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + entry, spinbutton.vertical.linked > text:drop(active):not(:only-child) + button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + menubutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + menubutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + dropdown > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + dropdown > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + colorbutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + colorbutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + fontbutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + fontbutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + filechooserbutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + filechooserbutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + combobox > box > button.combo, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + combobox > box > button.combo, spinbutton.vertical.linked > entry:drop(active):not(:only-child) + text, .linked.vertical > entry:drop(active):not(:only-child) + spinbutton:not(.vertical), .linked.vertical > entry:drop(active):not(:only-child) + entry, .linked.vertical > entry:drop(active):not(:only-child) + button, .linked.vertical > entry:drop(active):not(:only-child) + menubutton > button, .linked.vertical > entry:drop(active):not(:only-child) + dropdown > button, .linked.vertical > entry:drop(active):not(:only-child) + colorbutton > button, .linked.vertical > entry:drop(active):not(:only-child) + fontbutton > button, .linked.vertical > entry:drop(active):not(:only-child) + filechooserbutton > button, .linked.vertical > entry:drop(active):not(:only-child) + combobox > box > button.combo { border-top-color: #2ec27e; } + +spinbutton.vertical > text.error, spinbutton.error:not(.vertical), entry.error { color: #cc0000; } + +treeview entry:focus-within:dir(rtl), treeview entry:focus-within:dir(ltr) { background-color: #ffffff; transition-property: color, background; } + +treeview entry.flat, treeview entry { border-radius: 0; background-image: none; background-color: #ffffff; } + +treeview entry.flat:focus-within, treeview entry:focus-within { border-color: #1b6acb; } + +/******************* Editable Labels * */ +editablelabel > stack > text { color: black; border-color: #877b6e; background-color: #ffffff; } + +/*********** Buttons * */ +@keyframes needs_attention { from { background-image: radial-gradient(farthest-side, #1b6acb 0%, rgba(27, 106, 203, 0) 0%); } + to { background-image: radial-gradient(farthest-side, #1b6acb 95%, rgba(27, 106, 203, 0)); } } + +notebook > header > tabs > arrow, windowcontrols button, button { min-height: 24px; min-width: 16px; padding: 4px 9px; border: 1px solid; border-radius: 5px; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); color: #272c2e; outline-color: rgba(27, 106, 203, 0.8); border-color: #877b6e; background-image: linear-gradient(to top, #fafaf9 2px, white); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +notebook > header > tabs > arrow, windowcontrols button, button { outline: 0 solid transparent; outline-offset: 4px; } + +notebook > header > tabs > arrow:focus:focus-visible, button:focus:focus-visible { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: -2px; } + +notebook > header > tabs > arrow:hover, button:hover { color: #272c2e; border-color: #877b6e; background-image: linear-gradient(to top, #dad6d2, #edebe9 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); -gtk-icon-filter: brightness(1.2); } + +notebook > header > tabs > arrow.keyboard-activating, notebook > header > tabs > arrow:active, notebook > header > tabs > arrow:checked, button.keyboard-activating, button:active, button:checked { color: #272c2e; border-color: #877b6e; background-image: image(#dfdbd8); box-shadow: none; transition-duration: 50ms; } + +notebook > header > tabs > arrow:checked:hover, button:checked:hover { color: #272c2e; border-color: #877b6e; background-image: image(#d6d1cd); box-shadow: none; } + +notebook > header > tabs > arrow:checked:active, button:checked:active { color: #272c2e; border-color: #877b6e; background-image: image(#cdc7c1); box-shadow: none; } + +notebook > header > tabs > arrow:backdrop, button.flat:backdrop, button:backdrop { color: #929595; border-color: #d5d0cc; background-image: image(#f6f5f4); box-shadow: none; transition: 200ms ease-out; } + +notebook > header > tabs > arrow:backdrop:not(:disabled), button.flat:backdrop:not(:disabled), button:backdrop:not(:disabled) { -gtk-icon-filter: none; } + +notebook > header > tabs > arrow:backdrop:active, notebook > header > tabs > arrow:backdrop:checked, button.flat:backdrop:active, button.flat:backdrop:checked, button:backdrop:active, button:backdrop:checked { color: #929595; border-color: #d5d0cc; background-image: image(#ebebeb); box-shadow: none; } + +notebook > header > tabs > arrow:backdrop:disabled, button.flat:backdrop:disabled, button:backdrop:disabled { color: #d4cfca; border-color: #d5d0cc; background-image: image(#fefefd); box-shadow: none; } + +notebook > header > tabs > arrow:backdrop:disabled:active, notebook > header > tabs > arrow:backdrop:disabled:checked, button.flat:backdrop:disabled:active, button.flat:backdrop:disabled:checked, button:backdrop:disabled:active, button:backdrop:disabled:checked { color: #d4cfca; border-color: #d5d0cc; background-image: image(#ebebeb); box-shadow: none; } + +notebook > header > tabs > arrow:disabled, button:disabled { color: #929495; border-color: #9e958b; background-image: image(#fefefd); -gtk-icon-filter: opacity(0.5); } + +notebook > header > tabs > arrow:disabled:active, notebook > header > tabs > arrow:disabled:checked, button:disabled:active, button:disabled:checked { color: #929495; border-color: #9e958b; background-image: image(#ebebeb); box-shadow: none; } + - button.sidebar-button, notebook > header > tabs > arrow, windowcontrols button, notebook > header > tabs > arrow.flat, button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; transition: none; } ++button.sidebar-button, notebook > header > tabs > arrow, windowcontrols button, .toolbar button, notebook > header > tabs > arrow.flat, button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; transition: none; } + - button.sidebar-button:hover, notebook > header > tabs > arrow:hover, windowcontrols button:hover, button.flat:hover { border-color: transparent; background-image: none; box-shadow: none; background-color: #dfdbd8; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-duration: 500ms; } ++button.sidebar-button:hover, notebook > header > tabs > arrow:hover, windowcontrols button:hover, .toolbar button:hover, button.flat:hover { border-color: transparent; background-image: none; box-shadow: none; background-color: #dfdbd8; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-duration: 500ms; } + - button.keyboard-activating.sidebar-button, notebook > header > tabs > arrow.keyboard-activating, windowcontrols button.keyboard-activating, button.sidebar-button:active, notebook > header > tabs > arrow:active, windowcontrols button:active, button.sidebar-button:checked, notebook > header > tabs > arrow:checked, windowcontrols button:checked, button.flat.keyboard-activating, button.flat:active, button.flat:checked { border-color: transparent; background-image: none; box-shadow: none; background-color: #d1ccc7; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } ++button.keyboard-activating.sidebar-button, notebook > header > tabs > arrow.keyboard-activating, windowcontrols button.keyboard-activating, .toolbar button.keyboard-activating, button.sidebar-button:active, notebook > header > tabs > arrow:active, windowcontrols button:active, .toolbar button:active, button.sidebar-button:checked, notebook > header > tabs > arrow:checked, windowcontrols button:checked, .toolbar button:checked, button.flat.keyboard-activating, button.flat:active, button.flat:checked { border-color: transparent; background-image: none; box-shadow: none; background-color: #d1ccc7; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + - button.sidebar-button:backdrop, notebook > header > tabs > arrow:backdrop, windowcontrols button:backdrop, button.sidebar-button:disabled, notebook > header > tabs > arrow:disabled, windowcontrols button:disabled, button.flat:backdrop, button.flat:disabled, button.flat:backdrop:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; } ++button.sidebar-button:backdrop, notebook > header > tabs > arrow:backdrop, windowcontrols button:backdrop, .toolbar button:backdrop, button.sidebar-button:disabled, notebook > header > tabs > arrow:disabled, windowcontrols button:disabled, .toolbar button:disabled, button.flat:backdrop, button.flat:disabled, button.flat:backdrop:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; } + +notebook > header > tabs > arrow.image-button, button.image-button { min-width: 24px; padding-left: 5px; padding-right: 5px; } + +notebook > header > tabs > arrow.text-button, button.text-button { padding-left: 16px; padding-right: 16px; } + +notebook > header > tabs > arrow.text-button.image-button, button.text-button.image-button { padding-left: 8px; padding-right: 8px; } + +notebook > header > tabs > arrow.text-button.image-button label, button.text-button.image-button label { padding-left: 8px; padding-right: 8px; } + +dropdown:drop(active) button.combo, combobox:drop(active) button.combo, notebook > header > tabs > arrow:drop(active), button:drop(active) { color: #2ec27e; border-color: #2ec27e; box-shadow: inset 0 0 0 1px #2ec27e; } + +row:selected button { border-color: #124787; } + +row:selected button.sidebar-button:not(:active):not(:checked):not(:hover):not(disabled), row:selected button.flat:not(:active):not(:checked):not(:hover):not(disabled) { color: #ffffff; border-color: transparent; } + +row:selected button.sidebar-button:not(:active):not(:checked):not(:hover):not(disabled):backdrop, row:selected button.flat:not(:active):not(:checked):not(:hover):not(disabled):backdrop { color: #fcfcfc; } + +button.osd { min-width: 26px; min-height: 32px; color: #eeeeec; border-radius: 5px; color: #eeeeec; outline-color: rgba(27, 106, 203, 0.8); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; border: none; box-shadow: none; } + +button.osd.image-button { min-width: 30px; } + +button.osd.image-button:only-child { margin: 4px; border-radius: 50%; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); } + +button.osd:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(27, 27, 27, 0.7)); background-clip: padding-box; border: none; box-shadow: none; } + +button.osd:active, button.osd:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(2, 2, 2, 0.7)); background-clip: padding-box; box-shadow: none; border: none; box-shadow: none; } + +.app-notification button, popover.background.touch-selection button, popover.background.magnifier button, .osd button { color: #eeeeec; outline-color: rgba(27, 106, 203, 0.8); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; } + +.app-notification button:hover, popover.background.touch-selection button:hover, popover.background.magnifier button:hover, .osd button:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(27, 27, 27, 0.7)); background-clip: padding-box; } + +.app-notification button:active, popover.background.touch-selection button:active, popover.background.magnifier button:active, .app-notification button:checked, popover.background.touch-selection button:checked, popover.background.magnifier button:checked, .osd button:active:backdrop, .osd button:active, .osd button:checked:backdrop, .osd button:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(2, 2, 2, 0.7)); background-clip: padding-box; box-shadow: none; } + +.app-notification button:disabled, popover.background.touch-selection button:disabled, popover.background.magnifier button:disabled, .osd button:disabled:backdrop, .osd button:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; } + +.app-notification button.flat, popover.background.touch-selection button.flat, popover.background.magnifier button.flat, .osd button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; box-shadow: none; -gtk-icon-shadow: 0 1px black; } + +.app-notification button.flat:hover, popover.background.touch-selection button.flat:hover, popover.background.magnifier button.flat:hover, .osd button.flat:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(27, 27, 27, 0.7)); background-clip: padding-box; } + +.app-notification button.flat:disabled, popover.background.touch-selection button.flat:disabled, popover.background.magnifier button.flat:disabled, .osd button.flat:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; background-image: none; border-color: transparent; box-shadow: none; } + +.app-notification button.flat:active, popover.background.touch-selection button.flat:active, popover.background.magnifier button.flat:active, .app-notification button.flat:checked, popover.background.touch-selection button.flat:checked, popover.background.magnifier button.flat:checked, .osd button.flat:active, .osd button.flat:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(2, 2, 2, 0.7)); background-clip: padding-box; box-shadow: none; } + +button.suggested-action { color: white; outline-color: white; border-color: #0f3b71; background-image: linear-gradient(to top, #1a66c2 2px, #1b6acb); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +button.suggested-action { outline: 0 solid transparent; outline-offset: 4px; } + +button.suggested-action:focus:focus-visible { outline-color: white; outline-width: 2px; outline-offset: -2px; } + +button.suggested-action.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #1b6acb; } + +button.suggested-action:hover { color: white; border-color: #124787; background-image: linear-gradient(to top, #114583, #1658a7 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +button.suggested-action:active, button.suggested-action:checked { color: white; border-color: #124787; background-image: image(#13498c); box-shadow: none; } + +button.suggested-action.flat:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: rgba(27, 106, 203, 0.8); } + +button.suggested-action:disabled { color: #929495; border-color: #9e958b; background-image: image(#fefefd); } + +button.suggested-action:disabled:active, button.suggested-action:disabled:checked { color: #aac5e4; border-color: #124787; background-image: image(#2b6dbc); box-shadow: none; } + +.osd button.suggested-action { color: #eeeeec; outline-color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(27, 106, 203, 0.5)); background-clip: padding-box; } + +.osd button.suggested-action:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(27, 106, 203, 0.7)); background-clip: padding-box; } + +.osd button.suggested-action:active:backdrop, .osd button.suggested-action:active, .osd button.suggested-action:checked:backdrop, .osd button.suggested-action:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(#1b6acb); background-clip: padding-box; box-shadow: none; } + +.osd button.suggested-action:disabled:backdrop, .osd button.suggested-action:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; } + +button.destructive-action { color: white; outline-color: white; border-color: #851015; background-image: linear-gradient(to top, #d71a23 2px, #e01b24); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +button.destructive-action { outline: 0 solid transparent; outline-offset: 4px; } + +button.destructive-action:focus:focus-visible { outline-color: white; outline-width: 2px; outline-offset: -2px; } + +button.destructive-action.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #e01b24; } + +button.destructive-action:hover { color: white; border-color: #9c1319; background-image: linear-gradient(to top, #971218, #bc171e 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +button.destructive-action:active, button.destructive-action:checked { color: white; border-color: #9c1319; background-image: image(#a0131a); box-shadow: none; } + +button.destructive-action.flat:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: rgba(224, 27, 36, 0.8); } + +button.destructive-action:disabled { color: #929495; border-color: #9e958b; background-image: image(#fefefd); } + +button.destructive-action:disabled:active, button.destructive-action:disabled:checked { color: #f1a5a8; border-color: #9c1319; background-image: image(#dc1d27); box-shadow: none; } + +.osd button.destructive-action { color: #eeeeec; outline-color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(224, 27, 36, 0.5)); background-clip: padding-box; } + +.osd button.destructive-action:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(224, 27, 36, 0.7)); background-clip: padding-box; } + +.osd button.destructive-action:active:backdrop, .osd button.destructive-action:active, .osd button.destructive-action:checked:backdrop, .osd button.destructive-action:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(#e01b24); background-clip: padding-box; box-shadow: none; } + +.osd button.destructive-action:disabled:backdrop, .osd button.destructive-action:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; } + +stackswitcher > button > label { padding: 0 6px; margin: 0 -6px; } + +stackswitcher > button > image { padding: 3px 6px; margin: -3px -6px; } + +button.font separator { background-color: transparent; } + +button.font > box { border-spacing: 6px; } + +button.font > box > box > label { font-weight: bold; } + +menubutton.circular button, button.circular { min-width: 32px; min-height: 32px; padding: 0; border-radius: 9999px; } + +menubutton.circular button label, button.circular label { padding: 0; } + +stacksidebar row.needs-attention > label, stackswitcher > button.needs-attention > label, stackswitcher > button.needs-attention > image { animation: needs_attention 150ms ease-in; background-image: radial-gradient(farthest-side, #1b6acb 96%, rgba(27, 106, 203, 0)); background-size: 6px 6px, 6px 6px; background-repeat: no-repeat; background-position: right 3px, right 4px; } + +stacksidebar row.needs-attention > label:backdrop, stackswitcher > button.needs-attention > label:backdrop, stackswitcher > button.needs-attention > image:backdrop { background-size: 6px 6px, 0 0; } + +stacksidebar row.needs-attention > label:dir(rtl), stackswitcher > button.needs-attention > label:dir(rtl), stackswitcher > button.needs-attention > image:dir(rtl) { background-position: left 3px, left 4px; } + +.linked:not(.vertical) > filechooserbutton > combobox:dir(rtl):not(:last-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(rtl):not(:last-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(rtl):not(:last-child) > box > button.combo, .linked:not(.vertical) > filechooserbutton > combobox:dir(ltr):not(:first-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(ltr):not(:first-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(ltr):not(:first-child) > box > button.combo, dropdown.linked button:nth-child(2):dir(ltr), combobox.linked button:nth-child(2):dir(ltr), .linked:not(.vertical) > menubutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > dropdown:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > colorbutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > fontbutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > filechooserbutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > menubutton:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > dropdown:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > colorbutton:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > fontbutton:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > filechooserbutton:dir(ltr):not(:first-child) > button, spinbutton.vertical.linked:not(.vertical) > text:dir(rtl):not(:last-child), .linked:not(.vertical) > spinbutton:dir(rtl):not(:last-child):not(.vertical), .linked:not(.vertical) > entry:dir(rtl):not(:last-child), .linked:not(.vertical) > button:dir(rtl):not(:last-child), spinbutton.vertical.linked:not(.vertical) > text:dir(ltr):not(:first-child), .linked:not(.vertical) > spinbutton:dir(ltr):not(:first-child):not(.vertical), .linked:not(.vertical) > entry:dir(ltr):not(:first-child), .linked:not(.vertical) > button:dir(ltr):not(:first-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; } + +.linked:not(.vertical) > filechooserbutton > combobox:dir(rtl):not(:first-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(rtl):not(:first-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(rtl):not(:first-child) > box > button.combo, .linked:not(.vertical) > filechooserbutton > combobox:dir(ltr):not(:last-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(ltr):not(:last-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(ltr):not(:last-child) > box > button.combo, dropdown.linked button:nth-child(2):dir(rtl), combobox.linked button:nth-child(2):dir(rtl), .linked:not(.vertical) > menubutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > dropdown:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > colorbutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > fontbutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > filechooserbutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > menubutton:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > dropdown:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > colorbutton:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > fontbutton:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > filechooserbutton:dir(ltr):not(:last-child) > button, spinbutton.vertical.linked:not(.vertical) > text:dir(rtl):not(:first-child), .linked:not(.vertical) > spinbutton:dir(rtl):not(:first-child):not(.vertical), .linked:not(.vertical) > entry:dir(rtl):not(:first-child), .linked:not(.vertical) > button:dir(rtl):not(:first-child), spinbutton.vertical.linked:not(.vertical) > text:dir(ltr):not(:last-child), .linked:not(.vertical) > spinbutton:dir(ltr):not(:last-child):not(.vertical), .linked:not(.vertical) > entry:dir(ltr):not(:last-child), .linked:not(.vertical) > button:dir(ltr):not(:last-child) { border-right-style: none; border-top-right-radius: 0; border-bottom-right-radius: 0; } + +.linked.vertical > filechooserbutton > combobox:not(:first-child) > box > button.combo, .linked.vertical > appchooserbutton > combobox:not(:first-child) > box > button.combo, .linked.vertical > combobox:not(:first-child) > box > button.combo, .linked.vertical > menubutton:not(:first-child) > button, .linked.vertical > dropdown:not(:first-child) > button, .linked.vertical > colorbutton:not(:first-child) > button, .linked.vertical > fontbutton:not(:first-child) > button, .linked.vertical > filechooserbutton:not(:first-child) > button, spinbutton.vertical.linked > text:not(:first-child), .linked.vertical > spinbutton:not(:first-child):not(.vertical), .linked.vertical > entry:not(:first-child), .linked.vertical > button:not(:first-child) { border-top-left-radius: 0; border-top-right-radius: 0; } + +.linked.vertical > filechooserbutton > combobox:not(:last-child) > box > button.combo, .linked.vertical > appchooserbutton > combobox:not(:last-child) > box > button.combo, .linked.vertical > combobox:not(:last-child) > box > button.combo, .linked.vertical > menubutton:not(:last-child) > button, .linked.vertical > dropdown:not(:last-child) > button, .linked.vertical > colorbutton:not(:last-child) > button, .linked.vertical > fontbutton:not(:last-child) > button, .linked.vertical > filechooserbutton:not(:last-child) > button, spinbutton.vertical.linked > text:not(:last-child), .linked.vertical > spinbutton:not(:last-child):not(.vertical), .linked.vertical > entry:not(:last-child), .linked.vertical > button:not(:last-child) { border-bottom-style: none; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } + - .scale-popup button:hover, button.link, button.link:hover, button.link:active, button.link:checked, popover.menu box.circular-buttons button.circular.image-button.model, list > row button.image-button:not(.flat), .toolbar button, modelbutton.flat { background-color: transparent; background-image: none; border-color: transparent; box-shadow: inset 0 1px rgba(255, 255, 255, 0), 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; } ++.scale-popup button:hover, button.link, button.link:hover, button.link:active, button.link:checked, popover.menu box.circular-buttons button.circular.image-button.model, list > row button.image-button:not(.flat), modelbutton.flat { background-color: transparent; background-image: none; border-color: transparent; box-shadow: inset 0 1px rgba(255, 255, 255, 0), 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; } + +/* menu buttons */ +modelbutton.flat { min-height: 26px; padding-left: 5px; padding-right: 5px; border-radius: 5px; } + +modelbutton.flat:hover { background-color: #e6e3e0; } + +modelbutton.flat:disabled { color: #929495; } + +modelbutton.flat arrow { background: none; min-width: 16px; min-height: 16px; opacity: 0.3; } + +modelbutton.flat arrow:hover { background: none; } + +modelbutton.flat arrow.left { -gtk-icon-source: -gtk-icontheme("go-previous-symbolic"); } + +modelbutton.flat arrow.right { -gtk-icon-source: -gtk-icontheme("go-next-symbolic"); } + +/* oldstyle toolbar buttons */ +.toolbar button { margin: 1px; } + - .toolbar button:hover { color: #272c2e; border-color: #877b6e; background-image: linear-gradient(to top, #dad6d2, #edebe9 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } - - .toolbar button:active { color: #272c2e; border-color: #877b6e; background-image: image(#dfdbd8); box-shadow: none; } - - .toolbar button:disabled { color: #929495; border-color: #9e958b; background-image: image(#fefefd); } - - .toolbar button:backdrop { color: #929595; border-color: #d5d0cc; background-image: image(#f6f5f4); box-shadow: none; } - - .toolbar button:backdrop:disabled { color: #d4cfca; border-color: #d5d0cc; background-image: image(#fefefd); box-shadow: none; } - +button.color { padding: 4px; } + +button.color > colorswatch:only-child { box-shadow: 0 1px rgba(0, 0, 0, 0.1); } + +button.color > colorswatch:only-child, button.color > colorswatch:only-child > overlay { border-radius: 0; } + +.osd button.color > colorswatch:only-child { box-shadow: none; } + +.osd button.color:disabled colorswatch:only-child, .osd button.color:active colorswatch:only-child, .osd button.color:checked colorswatch:only-child, button.color:disabled colorswatch:only-child, button.color:active colorswatch:only-child, button.color:checked colorswatch:only-child { box-shadow: none; } + +/* list buttons */ +/* tone down as per new designs, see issue #1473 */ +popover.menu box.circular-buttons button.circular.image-button.model, list > row button.image-button:not(.flat) { border: 1px solid rgba(135, 123, 110, 0.5); } + +popover.menu box.circular-buttons button.circular.image-button.model:hover, list > row button.image-button:not(.flat):hover { color: #272c2e; border-color: #877b6e; background-image: linear-gradient(to top, #dad6d2, #edebe9 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +popover.menu box.circular-buttons button.circular.image-button.model:active, popover.menu box.circular-buttons button.circular.image-button.model:checked, list > row button.image-button:not(.flat):active, list > row button.image-button:not(.flat):checked { color: #272c2e; border-color: #877b6e; background-image: image(#dfdbd8); box-shadow: none; } + +popover.menu box.circular-buttons button.suggested-action.circular.image-button.model, list > row button.image-button.suggested-action:not(.flat) { color: white; outline-color: white; border-color: #0f3b71; background-image: linear-gradient(to top, #1a66c2 2px, #1b6acb); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +popover.menu box.circular-buttons button.suggested-action.circular.image-button.model, list > row button.image-button.suggested-action:not(.flat) { outline: 0 solid transparent; outline-offset: 4px; } + +popover.menu box.circular-buttons button.suggested-action.circular.image-button.model:focus:focus-visible, list > row button.image-button.suggested-action:not(.flat):focus:focus-visible { outline-color: white; outline-width: 2px; outline-offset: -2px; } + +popover.menu box.circular-buttons button.destructive-action.circular.image-button.model, list > row button.image-button.destructive-action:not(.flat) { color: white; outline-color: white; border-color: #851015; background-image: linear-gradient(to top, #d71a23 2px, #e01b24); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +popover.menu box.circular-buttons button.destructive-action.circular.image-button.model, list > row button.image-button.destructive-action:not(.flat) { outline: 0 solid transparent; outline-offset: 4px; } + +popover.menu box.circular-buttons button.destructive-action.circular.image-button.model:focus:focus-visible, list > row button.image-button.destructive-action:not(.flat):focus:focus-visible { outline-color: white; outline-width: 2px; outline-offset: -2px; } + +/********* Links * */ +button.link, link { color: #1b6acb; text-decoration: underline; } + +button.link:visited, link:visited { color: #15539e; } + +*:selected button.link:visited, *:selected link:visited { color: #a1bad8; } + +button.link:hover, link:hover { color: #3584e4; } + +*:selected button.link:hover, *:selected link:hover { color: #ebf3fc; } + +button.link:active, link:active { color: #1b6acb; } + +*:selected button.link:active, *:selected link:active { color: #d1e1f5; } + +button.link:disabled, link:disabled { color: rgba(115, 115, 115, 0.8); } + +button.link:selected, *:selected button.link, link:selected, *:selected link { color: #d1e1f5; } + +link { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +link { outline: 0 solid transparent; outline-offset: 4px; } + +link:focus:focus-visible { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: -2px; } + +button.link, button.link:hover, button.link:active, button.link:checked { text-shadow: none; } + +button.link > label { text-decoration: underline; } + +/***************** GtkSpinButton * */ +spinbutton { font-feature-settings: "tnum"; } + +spinbutton:not(.vertical) { padding: 0; border-spacing: 0; /* :not here just to bump specificity above that of the list button styling */ } + +.osd spinbutton:not(.vertical) > text, spinbutton:not(.vertical) > text { min-width: 28px; margin: 0; background: none; background-color: transparent; border: none; border-radius: 0; box-shadow: none; padding: 6px; } + +.osd spinbutton:not(.vertical) > text:backdrop:disabled, spinbutton:not(.vertical) > text:backdrop:disabled { background-color: transparent; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat), spinbutton:not(.vertical) > button.image-button.down:not(.flat) { min-height: 16px; margin: 0; padding-bottom: 0; padding-top: 0; color: #3d4143; background-image: none; border-style: none none none solid; border-color: rgba(135, 123, 110, 0.3); border-radius: 0; box-shadow: none; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl), spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl) { border-style: none solid none none; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):hover, spinbutton:not(.vertical) > button.image-button.down:not(.flat):hover { color: #272c2e; background-color: #f1f0ee; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):disabled, spinbutton:not(.vertical) > button.image-button.down:not(.flat):disabled { color: rgba(146, 148, 149, 0.3); background-color: transparent; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):active, spinbutton:not(.vertical) > button.image-button.down:not(.flat):active { background-color: rgba(0, 0, 0, 0.1); box-shadow: inset 0 2px 3px -1px rgba(0, 0, 0, 0.2); } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(ltr):last-child, spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(ltr):last-child { border-radius: 0 5px 5px 0; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl):first-child, spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl):first-child { border-radius: 5px 0 0 5px; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat), .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat) { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #eeeeec; border-style: none none none solid; border-color: rgba(0, 0, 0, 0.4); border-radius: 0; box-shadow: none; -gtk-icon-shadow: 0 1px black; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl), .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl) { border-style: none solid none none; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):hover, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):hover { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #eeeeec; border-color: rgba(0, 0, 0, 0.5); background-color: rgba(27, 27, 27, 0.7); -gtk-icon-shadow: 0 1px black; box-shadow: none; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):disabled, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #919190; border-color: rgba(0, 0, 0, 0.5); -gtk-icon-shadow: none; box-shadow: none; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(ltr):last-child, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(ltr):last-child { border-radius: 0 5px 5px 0; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl):first-child, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl):first-child { border-radius: 5px 0 0 5px; } + +spinbutton.vertical:disabled { color: #929495; } + +spinbutton.vertical:drop(active) { border-color: transparent; box-shadow: none; } + +spinbutton.vertical > text { min-height: 32px; min-width: 32px; padding: 0; border-radius: 0; } + +spinbutton.vertical > text > block-cursor { color: #ffffff; background-color: black; } + +spinbutton.vertical > button { min-height: 32px; min-width: 32px; padding: 0; } + +spinbutton.vertical > button.up { border-bottom-style: none; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } + +spinbutton.vertical > button.down { border-top-style: none; border-top-left-radius: 0; border-top-right-radius: 0; } + +.osd spinbutton.vertical > button:first-child { color: #eeeeec; outline-color: rgba(27, 106, 203, 0.8); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; } + +.osd spinbutton.vertical > button:first-child:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(27, 27, 27, 0.7)); background-clip: padding-box; } + +.osd spinbutton.vertical > button:first-child:active { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(2, 2, 2, 0.7)); background-clip: padding-box; box-shadow: none; } + +.osd spinbutton.vertical > button:first-child:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; } + +treeview spinbutton:not(.vertical) { min-height: 0; border-style: none; border-radius: 0; } + +treeview spinbutton:not(.vertical) > text { min-height: 0; padding: 1px 2px; } + +/************** ComboBoxes * */ +dropdown > popover.menu.background > contents { padding: 0; } + +dropdown > button > box { border-spacing: 6px; } + +dropdown > button > box > stack > row.activatable:hover { background: none; box-shadow: none; } + +dropdown arrow, combobox arrow { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); min-height: 16px; min-width: 16px; } + +dropdown > popover.menu > contents modelbutton, combobox > popover.menu > contents modelbutton { padding-left: 9px; padding-right: 9px; } + +dropdown:drop(active), combobox:drop(active) { box-shadow: none; } + +dropdown popover, combobox popover { margin-top: 6px; padding: 0; } + +dropdown popover listview, combobox popover listview { margin: 8px 0; } + +dropdown popover listview > row.activatable, combobox popover listview > row.activatable { padding: 8px; } + +dropdown popover listview > row.activatable:selected, dropdown popover listview > row.activatable:selected:hover, combobox popover listview > row.activatable:selected, combobox popover listview > row.activatable:selected:hover { outline-color: white; color: black; background-color: #e6e3e0; box-shadow: none; } + +dropdown popover .dropdown-searchbar, combobox popover .dropdown-searchbar { padding: 6px; border-bottom: 1px solid #877b6e; } + +/************ Toolbars * */ +searchbar > revealer > box, .toolbar, toolbar { padding: 4px; border-spacing: 4px; background-color: #fdfdfc; } + +.osd .toolbar, .osd toolbar { background-color: transparent; } + +.toolbar.osd, toolbar.osd { padding: 13px; border: none; border-radius: 5px; background-color: rgba(53, 53, 53, 0.7); } + +.toolbar.osd.left, .toolbar.osd.right, .toolbar.osd.top, .toolbar.osd.bottom, toolbar.osd.left, toolbar.osd.right, toolbar.osd.top, toolbar.osd.bottom { border-radius: 0; } + +.toolbar.horizontal > separator, toolbar.horizontal > separator { margin: 4px 0; } + +.toolbar.vertical > separator, toolbar.vertical > separator { margin: 0 4px; } + +searchbar > revealer > box { padding: 6px; border-spacing: 6px; border-width: 0 0 1px; } + +searchbar > revealer > box { border-style: solid; border-color: #877b6e; background-color: #d9d6d2; } + +searchbar > revealer > box:backdrop { border-color: #d5d0cc; background-color: #eae8e6; box-shadow: none; transition: 200ms ease-out; } + +/************** GtkInfoBar * */ +infobar > revealer > box { padding: 8px; border-spacing: 12px; } + +infobar.action:hover > revealer > box { background-color: white; } + +infobar.info > revealer > box, infobar.question > revealer > box, infobar.warning > revealer > box, infobar.error > revealer > box { border-bottom: 1px solid #93877b; background-color: white; } + +infobar .close, searchbar .close { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; min-width: 16px; min-height: 16px; padding: 4px; border-radius: 50%; } + +infobar .close:hover, searchbar .close:hover { color: #272c2e; border-color: #877b6e; background-image: linear-gradient(to top, #dad6d2, #edebe9 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +/***************** Title buttons * */ +windowcontrols { border-spacing: 6px; } + +windowcontrols.start:not(.empty):dir(ltr), windowcontrols.end:not(.empty):dir(rtl) { margin-right: 7px; } + +windowcontrols.start:not(.empty):dir(rtl), windowcontrols.end:not(.empty):dir(ltr) { margin-left: 7px; } + +windowcontrols button { border-radius: 9999px; padding: 6px; margin: 0 2px; min-width: 0; min-height: 0; } + +windowcontrols button:hover { border-color: transparent; background-image: none; box-shadow: none; background-color: #d1ccc7; } + +windowcontrols button:active, windowcontrols button:checked { border-color: transparent; background-image: none; box-shadow: none; background-color: #bab3ab; } + +/*************** Header bars * */ +.titlebar:not(headerbar), headerbar { padding: 0 6px; min-height: 46px; border-width: 0 0 1px; border-style: solid; border-color: #6e645a; border-radius: 0; background: #e6e3e0 linear-gradient(to top, #e1dedb, #e8e6e3); /* Darken switchbuttons for headerbars. issue #1588 */ } + +.titlebar:backdrop:not(headerbar), headerbar:backdrop { border-color: #d5d0cc; background-color: #fdfdfc; background-image: none; transition: 200ms ease-out; } + +.titlebar:not(headerbar) .title, headerbar .title { padding-left: 12px; padding-right: 12px; font-weight: bold; } + +.titlebar:not(headerbar) .subtitle, headerbar .subtitle { font-size: smaller; padding-left: 12px; padding-right: 12px; } + +.titlebar:not(headerbar) stackswitcher > button:checked, .titlebar:not(headerbar) button.toggle:checked, headerbar stackswitcher > button:checked, headerbar button.toggle:checked { background: image(#d6d1cd); border-color: #7e7367; border-top-color: #70665c; } + +.titlebar:not(headerbar) stackswitcher > button:checked:backdrop, .titlebar:not(headerbar) button.toggle:checked:backdrop, headerbar stackswitcher > button:checked:backdrop, headerbar button.toggle:checked:backdrop { color: #929595; border-color: #d5d0cc; background-image: image(#ebebeb); box-shadow: none; } + +.tiled .titlebar:not(headerbar), .tiled-top .titlebar:not(headerbar), .tiled-left .titlebar:not(headerbar), .tiled-right .titlebar:not(headerbar), .tiled-bottom .titlebar:not(headerbar), .maximized .titlebar:not(headerbar), .fullscreen .titlebar:not(headerbar), .tiled headerbar, .tiled-top headerbar, .tiled-left headerbar, .tiled-right headerbar, .tiled-bottom headerbar, .maximized headerbar, .fullscreen headerbar { border-radius: 0; } + +.default-decoration.titlebar:not(headerbar), headerbar.default-decoration { min-height: 28px; padding: 4px; } + +.default-decoration.titlebar:not(headerbar) windowcontrols button, .default-decoration.titlebar:not(headerbar) windowcontrols menubutton, headerbar.default-decoration windowcontrols button, headerbar.default-decoration windowcontrols menubutton { min-height: 26px; min-width: 26px; margin: 0; padding: 0; } + +.default-decoration.titlebar:not(headerbar) windowcontrols menubutton button, headerbar.default-decoration windowcontrols menubutton button { min-height: 20px; min-width: 20px; margin: 0; padding: 4px; } + +.solid-csd .titlebar:dir(rtl):not(headerbar), .solid-csd .titlebar:dir(ltr):not(headerbar), .solid-csd headerbar:backdrop:dir(rtl), .solid-csd headerbar:backdrop:dir(ltr), .solid-csd headerbar:dir(rtl), .solid-csd headerbar:dir(ltr) { margin-left: -1px; margin-right: -1px; margin-top: -1px; border-radius: 0; box-shadow: none; } + +headerbar > windowhandle > box, headerbar > windowhandle > box > box.start, headerbar > windowhandle > box > box.end { border-spacing: 6px; } + +headerbar entry, headerbar spinbutton, headerbar separator:not(.sidebar), headerbar button, headerbar menubutton { margin-top: 6px; margin-bottom: 6px; } + +headerbar menubutton > button { margin-top: 0px; margin-bottom: 0px; } + +headerbar switch { margin-top: 10px; margin-bottom: 10px; } + +window.csd > .titlebar:not(headerbar) { padding: 0; background-color: transparent; background-image: none; border-style: none; border-color: transparent; } + +.titlebar:not(headerbar) separator { background-color: #877b6e; } + +window.devel headerbar.titlebar { background: #fdfdfc cross-fade(10% -gtk-icontheme("system-run-symbolic"), image(transparent)) 90% 0/256px 256px no-repeat, linear-gradient(to right, transparent 65%, rgba(27, 106, 203, 0.2)), linear-gradient(to top, #dfdcd8, #e6e3e0 3px, #f4f2f1); } + +window.devel headerbar.titlebar:backdrop { background: #fdfdfc cross-fade(10% -gtk-icontheme("system-run-symbolic"), image(transparent)) 90% 0/256px 256px no-repeat, image(#fdfdfc); /* background-color would flash */ } + +/************ Pathbars * */ +pathbar > button.text-button, pathbar > button.image-button, pathbar > button { padding-left: 4px; padding-right: 4px; } + +pathbar > button.text-button.image-button label { padding-left: 0; padding-right: 0; } + +pathbar > button.text-button.image-button label:last-child, pathbar > button label:last-child { padding-right: 8px; } + +pathbar > button.text-button.image-button label:first-child, pathbar > button label:first-child { padding-left: 8px; } + +pathbar > button image { padding-left: 4px; padding-right: 4px; } + +pathbar > button.slider-button { padding-left: 0; padding-right: 0; } + +/************** Tree Views * */ +columnview.view, treeview.view { border-left-color: #9f958b; border-top-color: #9f958b; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +columnview.view, treeview.view { outline: 0 solid transparent; outline-offset: 4px; } + +columnview.view:focus:focus-visible, treeview.view:focus:focus-visible { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: -2px; } + +columnview.view:selected:focus, columnview.view:selected, treeview.view:selected:focus, treeview.view:selected { border-radius: 0; outline-color: white; } + +columnview.view:disabled, treeview.view:disabled { color: #929495; } + +columnview.view:disabled:selected, treeview.view:disabled:selected { color: #76a6e0; } + +columnview.view:disabled:selected:backdrop, treeview.view:disabled:selected:backdrop { color: #5f96da; } + +columnview.view.separator, treeview.view.separator { min-height: 2px; color: #9f958b; } + +columnview.view:backdrop, treeview.view:backdrop { border-left-color: #ddd9d6; border-top: #ddd9d6; } + +columnview.view:drop(active), treeview.view:drop(active) { box-shadow: none; } + +columnview.view > dndtarget:drop(active), treeview.view > dndtarget:drop(active) { border-style: solid none; border-width: 1px; border-color: #124787; } + +columnview.view > dndtarget.after:drop(active), treeview.view > dndtarget.after:drop(active) { border-top-style: none; } + +columnview.view > dndtarget.before:drop(active), treeview.view > dndtarget.before:drop(active) { border-bottom-style: none; } + +columnview.view.expander, treeview.view.expander { min-width: 16px; min-height: 16px; -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); color: #4d4d4d; } + +columnview.view.expander:dir(rtl), treeview.view.expander:dir(rtl) { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl"); } + +columnview.view.expander:hover, treeview.view.expander:hover { color: black; } + +columnview.view.expander:selected, treeview.view.expander:selected { color: #bbd2ef; } + +columnview.view.expander:selected:hover, treeview.view.expander:selected:hover { color: #ffffff; } + +columnview.view.expander:checked, treeview.view.expander:checked { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +columnview.view.progressbar, treeview.view.progressbar { color: #ffffff; background-color: #1b6acb; background-image: image(#1b6acb); box-shadow: none; } + +columnview.view.progressbar:selected:focus, columnview.view.progressbar:selected, treeview.view.progressbar:selected:focus, treeview.view.progressbar:selected { color: #1b6acb; background-image: image(#ffffff); } + +columnview.view.progressbar:selected:focus:backdrop, columnview.view.progressbar:selected:backdrop, treeview.view.progressbar:selected:focus:backdrop, treeview.view.progressbar:selected:backdrop { color: #1b6acb; background-color: #fcfcfc; } + +columnview.view.trough, treeview.view.trough { background-color: rgba(39, 44, 46, 0.1); } + +columnview.view.trough:selected:focus, columnview.view.trough:selected, treeview.view.trough:selected:focus, treeview.view.trough:selected { background-color: rgba(255, 255, 255, 0.3); } + +columnview.view > header > button, treeview.view > header > button { color: #939696; background-color: #ffffff; font-weight: bold; text-shadow: none; box-shadow: none; } + +columnview.view > header > button:hover, treeview.view > header > button:hover { color: #5d6162; box-shadow: none; transition: none; } + +columnview.view > header > button:active, treeview.view > header > button:active { color: #272c2e; transition: none; } + +columnview.view > header > button sort-indicator, treeview.view > header > button sort-indicator { min-height: 16px; min-width: 16px; } + +columnview.view > header > button sort-indicator.ascending, treeview.view > header > button sort-indicator.ascending { -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); } + +columnview.view > header > button sort-indicator.descending, treeview.view > header > button sort-indicator.descending { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +columnview.view button.dnd:active, columnview.view button.dnd:selected, columnview.view button.dnd:hover, columnview.view button.dnd, columnview.view header.button.dnd:active, columnview.view header.button.dnd:selected, columnview.view header.button.dnd:hover, columnview.view header.button.dnd, treeview.view button.dnd:active, treeview.view button.dnd:selected, treeview.view button.dnd:hover, treeview.view button.dnd, treeview.view header.button.dnd:active, treeview.view header.button.dnd:selected, treeview.view header.button.dnd:hover, treeview.view header.button.dnd { padding: 0 6px; color: #ffffff; background-image: none; background-color: #1b6acb; border-style: none; border-radius: 0; box-shadow: inset 0 0 0 1px #ffffff; text-shadow: none; transition: none; } + +columnview.view acceleditor > label, treeview.view acceleditor > label { background-color: #1b6acb; } + +columnview.view > header > button, treeview.view > header > button, columnview.view > header > button:hover, treeview.view > header > button:hover, columnview.view > header > button:active, treeview.view > header > button:active { padding: 0 6px; background-image: none; border-style: none none solid solid; border-color: #9f958b; border-radius: 0; text-shadow: none; } + +columnview.view > header > button:disabled, treeview.view > header > button:disabled { border-color: #fdfdfc; background-image: none; } + +columnview.view > header > button:last-child, treeview.view > header > button:last-child { border-right-style: none; } + +/*************** Popovers * */ +popover.background { background-color: transparent; font: initial; } + +popover.background > arrow, popover.background > contents { background-color: #ffffff; background-clip: padding-box; border: 1px solid rgba(0, 0, 0, 0.23); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); } + +popover.background:backdrop { background-color: transparent; } + +popover.background > contents { padding: 8px; border-radius: 9px; } + +popover.background > contents > list, popover.background > contents > .view, popover.background > contents > iconview, popover.background > contents > toolbar { border-style: none; background-color: transparent; } + +popover.background > contents separator { background-color: #aaa299; margin: 3px; } + +popover.background > contents list separator { margin: 0; } + +.osd popover.background, popover.background.touch-selection, popover.background.magnifier { background-color: transparent; } + +.osd popover.background > arrow, .osd popover.background > contents, popover.background.touch-selection > arrow, popover.background.touch-selection > contents, popover.background.magnifier > arrow, popover.background.magnifier > contents { border: 1px solid rgba(255, 255, 255, 0.1); box-shadow: none; } + +magnifier { background-color: #ffffff; } + +/********************** Popover Base Menus * */ +popover.menu { padding: 0; } + +popover.menu box.inline-buttons { padding: 0 12px; } + +popover.menu box.inline-buttons button.image-button.model { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; min-height: 30px; min-width: 30px; padding: 0; border: none; outline: none; transition: none; } + +popover.menu box.inline-buttons button.image-button.model:selected { background: image(#e6e3e0); } + +popover.menu box.circular-buttons { padding: 12px 12px 6px; } + +popover.menu box.circular-buttons button.circular.image-button.model { padding: 11px; } + +popover.menu box.circular-buttons button.circular.image-button.model:focus { background-color: #e6e3e0; border-color: #e6e3e0; } + +popover.menu > arrow, popover.menu.background > contents { background-color: #ffffff; padding: 5px; } + +popover.menu.background separator { margin: 6px 0; } + +popover.menu accelerator { color: alpha(currentColor,0.55); } + +popover.menu accelerator:dir(ltr) { margin-left: 12px; } + +popover.menu accelerator:dir(rtl) { margin-right: 12px; } + +popover.menu check, popover.menu radio { transform: scale(0.8); border-width: 1.2px; border-color: transparent; box-shadow: none; background-image: image(transparent); color: black; } + +popover.menu check:hover, popover.menu radio:hover { transform: scale(0.8); border-width: 1.2px; color: black; box-shadow: none; background-image: image(transparent); } + +popover.menu check:active, popover.menu radio:active { transform: scale(0.8); border-width: 1.2px; color: black; box-shadow: none; background-image: image(transparent); } + +popover.menu radio { border-color: #877b6e; } + +popover.menu radio:active { border-color: rgba(135, 123, 110, 0.5); } + +popover.menu arrow.left, popover.menu radio.left, popover.menu check.left { margin-left: -2px; margin-right: 6px; } + +popover.menu arrow.right, popover.menu radio.right, popover.menu check.right { margin-left: 6px; margin-right: -2px; } + +popover.menu modelbutton { min-height: 30px; min-width: 40px; padding: 0 12px; border-radius: 5px; } + +popover.menu modelbutton:selected { color: black; background-color: #e6e3e0; } + +popover.menu modelbutton:selected:active { background-color: #ddd9d5; } + +popover.menu label.title { font-weight: bold; padding: 4px 32px; } + +menubar { padding: 0px; box-shadow: inset 0 -1px rgba(0, 0, 0, 0.1); } + +menubar > item { min-height: 16px; padding: 4px 8px; } + +menubar > item:selected { box-shadow: inset 0 -3px #1b6acb; color: #1b6acb; } + +menubar > item:disabled { color: #929495; box-shadow: none; } + +menubar > item popover.menu.background > contents { padding: 5px; } + +menubar > item popover.menu popover.menu { padding: 0 0 4px 0; } + +menubar > item popover.menu.background popover.menu.background > contents { margin: 0; border-radius: 9px; } + +/************* Notebooks * */ +notebook { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +notebook > header > tabs > tab:checked { outline: 0 solid transparent; outline-offset: 4px; } + +notebook:focus:focus-visible > header > tabs > tab:checked { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: -2px; } + +notebook > header { padding: 1px; border-color: #877b6e; border-width: 1px; background-color: #e1dedb; } + +notebook > header > tabs { margin: -1px; } + +notebook > header.top { border-bottom-style: solid; } + +notebook > header.top > tabs { margin-bottom: -2px; } + +notebook > header.top > tabs > tab:hover { box-shadow: inset 0 -4px #877b6e; } + +notebook > header.top > tabs > tab:checked { box-shadow: inset 0 -4px #1b6acb; } + +notebook > header.bottom { border-top-style: solid; } + +notebook > header.bottom > tabs { margin-top: -2px; } + +notebook > header.bottom > tabs > tab:hover { box-shadow: inset 0 4px #877b6e; } + +notebook > header.bottom > tabs > tab:checked { box-shadow: inset 0 4px #1b6acb; } + +notebook > header.left { border-right-style: solid; } + +notebook > header.left > tabs { margin-right: -2px; } + +notebook > header.left > tabs > tab:hover { box-shadow: inset -4px 0 #877b6e; } + +notebook > header.left > tabs > tab:checked { box-shadow: inset -4px 0 #1b6acb; } + +notebook > header.right { border-left-style: solid; } + +notebook > header.right > tabs { margin-left: -2px; } + +notebook > header.right > tabs > tab:hover { box-shadow: inset 4px 0 #877b6e; } + +notebook > header.right > tabs > tab:checked { box-shadow: inset 4px 0 #1b6acb; } + +notebook > header.top > tabs > arrow { border-top-style: none; } + +notebook > header.bottom > tabs > arrow { border-bottom-style: none; } + +notebook > header.top > tabs > arrow, notebook > header.bottom > tabs > arrow { margin-left: -5px; margin-right: -5px; padding-left: 4px; padding-right: 4px; } + +notebook > header.top > tabs > arrow.down, notebook > header.bottom > tabs > arrow.down { -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); } + +notebook > header.top > tabs > arrow.up, notebook > header.bottom > tabs > arrow.up { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } + +notebook > header.left > tabs > arrow { border-left-style: none; } + +notebook > header.right > tabs > arrow { border-right-style: none; } + +notebook > header.left > tabs > arrow, notebook > header.right > tabs > arrow { margin-top: -5px; margin-bottom: -5px; padding-top: 4px; padding-bottom: 4px; } + +notebook > header.left > tabs > arrow.down, notebook > header.right > tabs > arrow.down { -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); } + +notebook > header.left > tabs > arrow.up, notebook > header.right > tabs > arrow.up { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +notebook > header > tabs > arrow { min-height: 16px; min-width: 16px; border-radius: 0; } + +notebook > header > tabs > arrow:hover:not(:active):not(:backdrop) { background-clip: padding-box; background-image: none; background-color: rgba(255, 255, 255, 0.3); border-color: transparent; box-shadow: none; } + +notebook > header > tabs > arrow:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; } + +notebook > header > tabs > tab { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); min-height: 30px; min-width: 30px; padding: 3px 12px; color: #272c2e; font-weight: normal; border-width: 1px; border-color: transparent; } + +notebook > header > tabs > tab:hover { color: #272c2e; background-color: #d8d4d0; } + +notebook > header > tabs > tab.reorderable-page:hover { border-color: rgba(135, 123, 110, 0.3); background-color: rgba(253, 253, 252, 0.2); } + +notebook > header > tabs > tab:not(:checked) { outline-color: transparent; } + +notebook > header > tabs > tab:checked { color: #272c2e; } + +notebook > header > tabs > tab.reorderable-page:checked { border-color: rgba(135, 123, 110, 0.5); background-color: rgba(253, 253, 252, 0.5); } + +notebook > header > tabs > tab.reorderable-page:checked:hover { background-color: rgba(253, 253, 252, 0.7); } + +notebook > header > tabs > tab button.flat { color: alpha(currentColor,0.3); padding: 0; margin-top: 4px; margin-bottom: 4px; min-width: 20px; min-height: 20px; } + +notebook > header > tabs > tab button.flat:hover { color: currentColor; } + +notebook > header > tabs > tab button.flat:last-child { margin-left: 4px; margin-right: -4px; } + +notebook > header > tabs > tab button.flat:first-child { margin-left: -4px; margin-right: 4px; } + +notebook > header.top > tabs, notebook > header.bottom > tabs { padding-left: 4px; padding-right: 4px; } + +notebook > header.top > tabs:not(:only-child), notebook > header.bottom > tabs:not(:only-child) { margin-left: 3px; margin-right: 3px; } + +notebook > header.top > tabs:not(:only-child):first-child, notebook > header.bottom > tabs:not(:only-child):first-child { margin-left: -1px; } + +notebook > header.top > tabs:not(:only-child):last-child, notebook > header.bottom > tabs:not(:only-child):last-child { margin-right: -1px; } + +notebook > header.top > tabs > tab, notebook > header.bottom > tabs > tab { margin-left: 4px; margin-right: 4px; } + +notebook > header.top > tabs > tab.reorderable-page, notebook > header.bottom > tabs > tab.reorderable-page { border-style: none solid; } + +notebook > header.left > tabs, notebook > header.right > tabs { padding-top: 4px; padding-bottom: 4px; } + +notebook > header.left > tabs:not(:only-child), notebook > header.right > tabs:not(:only-child) { margin-top: 3px; margin-bottom: 3px; } + +notebook > header.left > tabs:not(:only-child):first-child, notebook > header.right > tabs:not(:only-child):first-child { margin-top: -1px; } + +notebook > header.left > tabs:not(:only-child):last-child, notebook > header.right > tabs:not(:only-child):last-child { margin-bottom: -1px; } + +notebook > header.left > tabs > tab, notebook > header.right > tabs > tab { margin-top: 4px; margin-bottom: 4px; } + +notebook > header.left > tabs > tab.reorderable-page, notebook > header.right > tabs > tab.reorderable-page { border-style: solid none; } + +notebook > header.top > tabs > tab { padding-bottom: 4px; } + +notebook > header.bottom > tabs > tab { padding-top: 4px; } + +notebook > stack:not(:only-child) { background-color: #ffffff; } + +/************** Scrollbars * */ +scrollbar { background-color: #cecece; transition: all 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +scrollbar.top { border-bottom: 1px solid #877b6e; } + +scrollbar.bottom { border-top: 1px solid #877b6e; } + +scrollbar.left { border-right: 1px solid #877b6e; } + +scrollbar.right { border-left: 1px solid #877b6e; } + +scrollbar > range > trough > slider { min-width: 8px; min-height: 8px; margin: -1px; border: 4px solid transparent; border-radius: 10px; background-clip: padding-box; background-color: #7e8182; transition: all 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +scrollbar > range > trough > slider:hover { background-color: #565b5c; } + +scrollbar > range > trough > slider:hover:active { background-color: #1b6acb; } + +scrollbar > range > trough > slider:disabled { background-color: transparent; } + +scrollbar > range.fine-tune > trough > slider { transition: none; min-width: 6px; min-height: 6px; } + +scrollbar > range.fine-tune.horizontal > trough > slider { border-width: 5px 4px; } + +scrollbar > range.fine-tune.vertical > trough > slider { border-width: 4px 5px; } + +scrollbar.overlay-indicator:not(.dragging):not(.hovering) { border-color: transparent; opacity: 0.4; background-color: transparent; } + +scrollbar.overlay-indicator:not(.dragging):not(.hovering) > range > trough > slider { margin: 0; min-width: 3px; min-height: 3px; background-color: #272c2e; border: 1px solid white; } + +scrollbar.overlay-indicator.horizontal:not(.dragging):not(.hovering) > range > trough > slider { margin: 0 2px; min-width: 40px; } + +scrollbar.overlay-indicator.vertical:not(.dragging):not(.hovering) > range > trough > slider { margin: 2px 0; min-height: 40px; } + +scrollbar.overlay-indicator.dragging, scrollbar.overlay-indicator.hovering { opacity: 0.8; } + +scrollbar.horizontal > range > trough > slider { min-width: 40px; } + +scrollbar.vertical > range > trough > slider { min-height: 40px; } + +treeview ~ scrollbar.vertical { border-top: 1px solid #877b6e; margin-top: -1px; } + +/********** Switch * */ +switch { font-weight: bold; font-size: smaller; border: 1px solid #877b6e; border-radius: 14px; color: #272c2e; background-color: #e1dedb; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; /* only show i / o for the accessible theme */ } + +switch { outline: 0 solid transparent; outline-offset: 4px; } + +switch:focus:focus-visible { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: 0; } + +headerbar switch { background-color: #cecac5; } + +switch:checked { color: #ffffff; border-color: #185fb4; background-color: #3584e4; } + +switch:disabled { color: #929495; border-color: #877b6e; background-color: #fefefd; text-shadow: none; } + +switch > slider { color: #272c2e; outline-color: rgba(27, 106, 203, 0.8); border-color: #877b6e; background-image: linear-gradient(to top, #fafaf9 2px, white); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); margin: -1px; min-width: 24px; min-height: 24px; border: 1px solid; border-color: #877b6e; border-radius: 50%; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +switch > image { color: transparent; } + +switch:hover > slider { color: #272c2e; border-color: #877b6e; background-image: linear-gradient(to top, #dad6d2, #edebe9 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +switch:checked > slider { border: 1px solid #185fb4; } + +switch:disabled > slider { color: #929495; border-color: #9e958b; background-image: image(#fefefd); } + +row:selected switch { outline-color: white; box-shadow: none; border-color: #185fb4; } + +row:selected switch > slider:checked, row:selected switch > slider { border-color: #185fb4; } + +/************************* Check and Radio items * */ +.view.content-view.check:not(list), iconview.content-view.check:not(list), .content-view .tile check:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #3584e4; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:hover:not(list), iconview.content-view.check:hover:not(list), .content-view .tile check:hover:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #3584e4; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:active:not(list), iconview.content-view.check:active:not(list), .content-view .tile check:active:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #3584e4; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:backdrop:not(list), iconview.content-view.check:backdrop:not(list), .content-view .tile check:backdrop:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #8d8d8d; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:checked:not(list), iconview.content-view.check:checked:not(list), .content-view .tile check:checked:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: #3584e4; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +.view.content-view.check:checked:hover:not(list), iconview.content-view.check:checked:hover:not(list), .content-view .tile check:checked:hover:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: #3584e4; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +.view.content-view.check:checked:active:not(list), iconview.content-view.check:checked:active:not(list), .content-view .tile check:checked:active:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: #3584e4; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +.view.content-view.check:backdrop:checked:not(list), iconview.content-view.check:backdrop:checked:not(list), .content-view .tile check:backdrop:checked:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: rgba(238, 238, 236, 0.8); background-color: #8d8d8d; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +checkbutton { border-spacing: 4px; border-radius: 5px; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +checkbutton { outline: 0 solid transparent; outline-offset: 4px; } + +checkbutton:focus:focus-visible { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: -2px; } + +checkbutton.text-button { padding: 4px; } + +check, radio { min-height: 14px; min-width: 14px; border: 1px solid; -gtk-icon-source: none; } + +check, radio { background-clip: padding-box; background-image: linear-gradient(to bottom, white 20%, white 90%); border-color: #6e645a; box-shadow: 0 1px rgba(0, 0, 0, 0.05); color: #ffffff; } + +check:hover, radio:hover { background-image: image(#f2f2f2); } + +check:active, radio:active { box-shadow: inset 0 1px rgba(0, 0, 0, 0.2); background-image: image(#d9d9d9); } + +check:disabled, radio:disabled { box-shadow: none; color: rgba(255, 255, 255, 0.7); } + +check:checked, radio:checked { background-clip: border-box; background-image: linear-gradient(to bottom, #4b92e7 20%, #3584e4 90%); border-color: #1b6acb; box-shadow: 0 1px rgba(0, 0, 0, 0.05); color: #ffffff; } + +check:checked:hover, radio:checked:hover { background-image: linear-gradient(to bottom, #5d9de9 10%, #478fe6 90%); } + +check:checked:active, radio:checked:active { box-shadow: inset 0 1px rgba(0, 0, 0, 0.2); background-image: image(#1f76e1); } + +check:checked:disabled, radio:checked:disabled { box-shadow: none; color: rgba(255, 255, 255, 0.7); } + +check:indeterminate, radio:indeterminate { background-clip: border-box; background-image: linear-gradient(to bottom, #4b92e7 20%, #3584e4 90%); border-color: #1b6acb; box-shadow: 0 1px rgba(0, 0, 0, 0.05); color: #ffffff; } + +check:indeterminate:hover, radio:indeterminate:hover { background-image: linear-gradient(to bottom, #5d9de9 10%, #478fe6 90%); } + +check:indeterminate:active, radio:indeterminate:active { box-shadow: inset 0 1px rgba(0, 0, 0, 0.2); background-image: image(#1f76e1); } + +check:indeterminate:disabled, radio:indeterminate:disabled { box-shadow: none; color: rgba(255, 255, 255, 0.7); } + +row:selected check, row:selected radio { border-color: #1b6acb; } + +.osd check, .osd radio { color: #eeeeec; outline-color: rgba(27, 106, 203, 0.8); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; } + +.osd check:hover, .osd radio:hover { color: #eeeeec; outline-color: rgba(27, 106, 203, 0.8); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; } + +.osd check:active, .osd radio:active { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(2, 2, 2, 0.7)); background-clip: padding-box; box-shadow: none; } + +.osd check:disabled, .osd radio:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; } + +check { border-radius: 3px; -gtk-icon-size: 14px; } + +check:checked { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets-hc/check-symbolic.symbolic.png")), -gtk-recolor(url("assets-hc/check@2-symbolic.symbolic.png"))); } + +check:indeterminate { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets-hc/dash-symbolic.symbolic.png")), -gtk-recolor(url("assets-hc/dash@2-symbolic.symbolic.png"))); } + +treeview.view radio:selected:focus, treeview.view radio:selected, radio { border-radius: 100%; -gtk-icon-size: 14px; } + +treeview.view radio:checked:selected, radio:checked { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets-hc/bullet-symbolic.symbolic.png")), -gtk-recolor(url("assets-hc/bullet@2-symbolic.symbolic.png"))); } + +treeview.view radio:indeterminate:selected, radio:indeterminate { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets-hc/dash-symbolic.symbolic.png")), -gtk-recolor(url("assets-hc/dash@2-symbolic.symbolic.png"))); } + +treeview.view check:selected:focus, treeview.view check:selected, treeview.view radio:selected:focus, treeview.view radio:selected { color: #ffffff; border-color: #124787; } + +/************ GtkScale * */ +progressbar > trough, scale > trough > fill, scale > trough { border: 1px solid #e1dedb; border-radius: 3px; background-color: #e1dedb; } + +headerbar progressbar > trough, headerbar scale > trough > fill, headerbar scale > trough { background-color: #cecac5; } + +progressbar > trough:disabled, scale > trough > fill:disabled, scale > trough:disabled { background-color: #fefefd; border-color: #9e958b; } + +row:selected progressbar > trough, row:selected scale > trough > fill, row:selected scale > trough { outline-color: white; border-color: #124787; } + +.osd progressbar > trough, .osd scale > trough > fill, .osd scale > trough { border-color: rgba(0, 0, 0, 0.7); background-color: rgba(0, 0, 0, 0.5); } + +.osd progressbar > trough:disabled, .osd scale > trough > fill:disabled, .osd scale > trough:disabled { background-color: rgba(71, 71, 71, 0.5); } + +progressbar > trough > progress, scale > trough > highlight { border: 1px solid #1b6acb; border-radius: 3px; background-color: #1b6acb; } + +progressbar > trough > progress:disabled, scale > trough > highlight:disabled { background-color: transparent; border-color: transparent; } + +row:selected progressbar > trough > progress, row:selected scale > trough > highlight { border-color: #124787; } + +.osd progressbar > trough > progress, .osd scale > trough > highlight { border-color: rgba(0, 0, 0, 0.7); } + +.osd progressbar > trough > progress:disabled, .osd scale > trough > highlight:disabled { border-color: transparent; } + +scale { min-height: 10px; min-width: 10px; padding: 12px; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +scale > trough { outline: 0 solid transparent; outline-offset: 16px; } + +scale:focus:focus-visible > trough { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: 10px; } + +scale > trough { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +scale > trough > fill, scale > trough > highlight { margin: -1px; } + +scale > trough > slider { min-height: 18px; min-width: 18px; margin: -9px; } + +scale.fine-tune.horizontal { padding-top: 9px; padding-bottom: 9px; min-height: 16px; } + +scale.fine-tune.vertical { padding-left: 9px; padding-right: 9px; min-width: 16px; } + +scale.fine-tune > trough > slider { margin: -6px; } + +scale.fine-tune > trough > fill, scale.fine-tune > trough > highlight, scale.fine-tune > trough { border-radius: 5px; } + +scale > trough > fill:disabled { border-color: transparent; background-color: transparent; } + +.osd scale > trough > fill { background-color: rgba(91, 91, 90, 0.775); } + +.osd scale > trough > fill:disabled { border-color: transparent; background-color: transparent; } + +scale > trough > slider { color: #272c2e; outline-color: rgba(27, 106, 203, 0.8); border-color: #877b6e; background-image: linear-gradient(to top, #fafaf9 2px, white); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); border-width: 1px; border-style: solid; border-radius: 100%; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: background, border, box-shadow; } + +scale > trough > slider:hover { color: #272c2e; border-color: #877b6e; background-image: linear-gradient(to top, #dad6d2, #edebe9 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +scale > trough > slider:active { border-color: #124787; } + +scale > trough > slider:disabled { color: #929495; border-color: #9e958b; background-image: image(#fefefd); } + +row:selected scale > trough > slider:disabled, row:selected scale > trough > slider { border-color: #124787; } + +.osd scale > trough > slider { color: #eeeeec; outline-color: rgba(27, 106, 203, 0.8); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; border-color: rgba(0, 0, 0, 0.7); background-color: #353535; } + +.osd scale > trough > slider:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(27, 27, 27, 0.7)); background-clip: padding-box; background-color: #353535; } + +.osd scale > trough > slider:active { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(2, 2, 2, 0.7)); background-clip: padding-box; box-shadow: none; background-color: #353535; } + +.osd scale > trough > slider:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; background-color: #353535; } + +scale > value { color: alpha(currentColor,0.55); font-feature-settings: "tnum"; } + +scale.horizontal > marks { color: alpha(currentColor,0.55); } + +scale.horizontal > marks.top { margin-bottom: 6px; } + +scale.horizontal > marks.bottom { margin-top: 6px; } + +scale.horizontal > marks indicator { background-color: currentColor; min-height: 6px; min-width: 1px; } + +scale.horizontal > value.left { margin-right: 9px; } + +scale.horizontal > value.right { margin-left: 9px; } + +scale.horizontal.fine-tune > marks.top { margin-top: 3px; } + +scale.horizontal.fine-tune > marks.bottom { margin-bottom: 3px; } + +scale.horizontal.fine-tune > marks indicator { min-height: 3px; } + +scale.vertical > marks { color: alpha(currentColor,0.55); } + +scale.vertical > marks.top { margin-right: 6px; } + +scale.vertical > marks.bottom { margin-left: 6px; } + +scale.vertical > marks indicator { background-color: currentColor; min-height: 1px; min-width: 6px; } + +scale.vertical > value.top { margin-bottom: 9px; } + +scale.vertical > value.bottom { margin-top: 9px; } + +scale.vertical.fine-tune > marks.top { margin-left: 3px; } + +scale.vertical.fine-tune > marks.bottom { margin-right: 3px; } + +scale.vertical.fine-tune > marks indicator { min-height: 3px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-above.png"), url("assets-hc/slider-horz-scale-has-marks-above@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-above-hover.png"), url("assets-hc/slider-horz-scale-has-marks-above-hover@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-above-active.png"), url("assets-hc/slider-horz-scale-has-marks-above-active@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-above-insensitive.png"), url("assets-hc/slider-horz-scale-has-marks-above-insensitive@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-below.png"), url("assets-hc/slider-horz-scale-has-marks-below@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-below-hover.png"), url("assets-hc/slider-horz-scale-has-marks-below-hover@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-below-active.png"), url("assets-hc/slider-horz-scale-has-marks-below-active@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-below-insensitive.png"), url("assets-hc/slider-horz-scale-has-marks-below-insensitive@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-above.png"), url("assets-hc/slider-vert-scale-has-marks-above@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-above-hover.png"), url("assets-hc/slider-vert-scale-has-marks-above-hover@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-above-active.png"), url("assets-hc/slider-vert-scale-has-marks-above-active@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-above-insensitive.png"), url("assets-hc/slider-vert-scale-has-marks-above-insensitive@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-below.png"), url("assets-hc/slider-vert-scale-has-marks-below@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-below-hover.png"), url("assets-hc/slider-vert-scale-has-marks-below-hover@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-below-active.png"), url("assets-hc/slider-vert-scale-has-marks-below-active@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets-hc/slider-vert-scale-has-marks-below-insensitive.png"), url("assets-hc/slider-vert-scale-has-marks-below-insensitive@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.color { min-height: 0; min-width: 0; } + +scale.color > trough { background-image: image(#877b6e); background-repeat: no-repeat; } + +scale.color.horizontal { padding: 0 0 15px 0; } + +scale.color.horizontal > trough { padding-bottom: 4px; background-position: 0 -3px; border-top-left-radius: 0; border-top-right-radius: 0; } + +scale.color.horizontal > trough > slider:dir(ltr):hover, scale.color.horizontal > trough > slider:dir(ltr):backdrop, scale.color.horizontal > trough > slider:dir(ltr):disabled, scale.color.horizontal > trough > slider:dir(ltr):backdrop:disabled, scale.color.horizontal > trough > slider:dir(ltr), scale.color.horizontal > trough > slider:dir(rtl):hover, scale.color.horizontal > trough > slider:dir(rtl):backdrop, scale.color.horizontal > trough > slider:dir(rtl):disabled, scale.color.horizontal > trough > slider:dir(rtl):backdrop:disabled, scale.color.horizontal > trough > slider:dir(rtl) { margin-bottom: -15px; margin-top: 6px; } + +scale.color.vertical:dir(ltr) { padding: 0 0 0 15px; } + +scale.color.vertical:dir(ltr) > trough { padding-left: 4px; background-position: 3px 0; border-bottom-right-radius: 0; border-top-right-radius: 0; } + +scale.color.vertical:dir(ltr) > trough > slider:hover, scale.color.vertical:dir(ltr) > trough > slider:backdrop, scale.color.vertical:dir(ltr) > trough > slider:disabled, scale.color.vertical:dir(ltr) > trough > slider:backdrop:disabled, scale.color.vertical:dir(ltr) > trough > slider { margin-left: -15px; margin-right: 6px; } + +scale.color.vertical:dir(rtl) { padding: 0 15px 0 0; } + +scale.color.vertical:dir(rtl) > trough { padding-right: 4px; background-position: -3px 0; border-bottom-left-radius: 0; border-top-left-radius: 0; } + +scale.color.vertical:dir(rtl) > trough > slider:hover, scale.color.vertical:dir(rtl) > trough > slider:backdrop, scale.color.vertical:dir(rtl) > trough > slider:disabled, scale.color.vertical:dir(rtl) > trough > slider:backdrop:disabled, scale.color.vertical:dir(rtl) > trough > slider { margin-right: -15px; margin-left: 6px; } + +scale.color.fine-tune.horizontal:dir(ltr), scale.color.fine-tune.horizontal:dir(rtl) { padding: 0 0 12px 0; } + +scale.color.fine-tune.horizontal:dir(ltr) > trough, scale.color.fine-tune.horizontal:dir(rtl) > trough { padding-bottom: 7px; background-position: 0 -6px; } + +scale.color.fine-tune.horizontal:dir(ltr) > trough > slider, scale.color.fine-tune.horizontal:dir(rtl) > trough > slider { margin-bottom: -15px; margin-top: 6px; } + +scale.color.fine-tune.vertical:dir(ltr) { padding: 0 0 0 12px; } + +scale.color.fine-tune.vertical:dir(ltr) > trough { padding-left: 7px; background-position: 6px 0; } + +scale.color.fine-tune.vertical:dir(ltr) > trough > slider { margin-left: -15px; margin-right: 6px; } + +scale.color.fine-tune.vertical:dir(rtl) { padding: 0 12px 0 0; } + +scale.color.fine-tune.vertical:dir(rtl) > trough { padding-right: 7px; background-position: -6px 0; } + +scale.color.fine-tune.vertical:dir(rtl) > trough > slider { margin-right: -15px; margin-left: 6px; } + +/***************** Progress bars * */ +progressbar { font-size: smaller; color: rgba(39, 44, 46, 0.4); font-feature-settings: "tnum"; } + +progressbar.horizontal > trough { min-width: 150px; } + +progressbar.horizontal > trough, progressbar.horizontal > trough > progress { min-height: 2px; } + +progressbar.vertical > trough { min-height: 80px; } + +progressbar.vertical > trough, progressbar.vertical > trough > progress { min-width: 2px; } + +progressbar.horizontal > trough > progress { margin: 0 -1px; } + +progressbar.vertical > trough > progress { margin: -1px 0; } + +progressbar > trough > progress { /* share most of scales' */ /* override insensitive that is specific to progress */ border-radius: 1.5px; } + +progressbar > trough > progress:disabled { background-color: #929495; border-color: #929495; } + +progressbar > trough > progress.left { border-top-left-radius: 5px; border-bottom-left-radius: 5px; } + +progressbar > trough > progress.right { border-top-right-radius: 5px; border-bottom-right-radius: 5px; } + +progressbar > trough > progress.top { border-top-right-radius: 5px; border-top-left-radius: 5px; } + +progressbar > trough > progress.bottom { border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; } + +progressbar.osd { min-width: 3px; min-height: 3px; background-color: transparent; } + +progressbar.osd > trough { border-style: none; border-radius: 0; background-color: transparent; box-shadow: none; } + +progressbar.osd > trough > progress { border-style: none; border-radius: 0; } + +progressbar > trough.empty > progress { all: unset; } + +/************* Level Bar * */ +levelbar.horizontal trough > block { min-height: 9px; border-radius: 5px; } + +levelbar.horizontal trough > block:dir(rtl) { border-radius: 0 5px 5px 0; } + +levelbar.horizontal trough > block:dir(ltr) { border-radius: 5px 0 0 5px; } + +levelbar.horizontal trough > block.empty, levelbar.horizontal trough > block.full { border-radius: 5px; } + +levelbar.horizontal.discrete trough > block { min-height: 2px; margin: 1px; min-width: 24px; border-radius: 0; } + +levelbar.horizontal.discrete trough > block:first-child { border-radius: 2px 0 0 2px; } + +levelbar.horizontal.discrete trough > block:last-child { border-radius: 0 2px 2px 0; } + +levelbar.vertical trough > block { min-width: 9px; border-radius: 5px; } + +levelbar.vertical.discrete > trough > block { min-width: 2px; margin: 1px 0; min-height: 32px; } + +levelbar > trough { padding: 0; } + +levelbar > trough > block { border: 1px solid; } + +levelbar > trough > block.low { border-color: #f57900; background-color: #f57900; } + +levelbar > trough > block.high, levelbar > trough > block:not(.empty) { border-color: #1b6acb; background-color: #1b6acb; } + +levelbar > trough > block.full { border-color: #33d17a; background-color: #33d17a; } + +levelbar > trough > block.empty { background-color: #f1f0ee; border-color: #f1f0ee; } + +/**************** Print dialog * */ +window.dialog.print drawing { color: #272c2e; background: none; border: none; padding: 0; } + +window.dialog.print drawing paper { background: white; color: #2e3436; border: 1px solid #877b6e; } + +window.dialog.print .dialog-action-box { margin: 12px; } + +/********** Frames * */ +frame, .frame { border: 1px solid #877b6e; } + +frame { border-radius: 8px; } + +frame > label { margin: 4px; } + +actionbar > revealer > box { padding: 6px; border-top: 1px solid #877b6e; } + +actionbar > revealer > box, actionbar > revealer > box > box.start, actionbar > revealer > box > box.end { border-spacing: 6px; } + +scrolledwindow > overshoot.top { background-image: radial-gradient(farthest-side at top, #6b6157 85%, rgba(107, 97, 87, 0)), radial-gradient(farthest-side at top, rgba(39, 44, 46, 0.07), rgba(39, 44, 46, 0)); background-size: 100% 3%, 100% 50%; background-repeat: no-repeat; background-position: top; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > overshoot.bottom { background-image: radial-gradient(farthest-side at bottom, #6b6157 85%, rgba(107, 97, 87, 0)), radial-gradient(farthest-side at bottom, rgba(39, 44, 46, 0.07), rgba(39, 44, 46, 0)); background-size: 100% 3%, 100% 50%; background-repeat: no-repeat; background-position: bottom; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > overshoot.left { background-image: radial-gradient(farthest-side at left, #6b6157 85%, rgba(107, 97, 87, 0)), radial-gradient(farthest-side at left, rgba(39, 44, 46, 0.07), rgba(39, 44, 46, 0)); background-size: 3% 100%, 50% 100%; background-repeat: no-repeat; background-position: left; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > overshoot.right { background-image: radial-gradient(farthest-side at right, #6b6157 85%, rgba(107, 97, 87, 0)), radial-gradient(farthest-side at right, rgba(39, 44, 46, 0.07), rgba(39, 44, 46, 0)); background-size: 3% 100%, 50% 100%; background-repeat: no-repeat; background-position: right; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > junction { background: #877b6e, linear-gradient(to bottom, transparent 1px, #cecece 1px), linear-gradient(to right, transparent 1px, #cecece 1px); } + +scrolledwindow > junction:dir(rtl) { background: #877b6e, linear-gradient(to bottom, transparent 1px, #cecece 1px), linear-gradient(to left, transparent 1px, #cecece 1px); } + +separator { background: #93877b; min-width: 1px; min-height: 1px; } + +/********* Lists * */ +listview, list { color: black; background-color: #ffffff; border-color: #877b6e; } + +listview:backdrop, list:backdrop { color: #323232; background-color: #fcfcfc; border-color: #d5d0cc; } + +listview > row, list > row { padding: 2px; } + +listview > row.expander, list > row.expander { padding: 0px; } + +listview > row.expander .row-header, list > row.expander .row-header { padding: 2px; } + +listview.horizontal row.separator, listview.separators.horizontal > row:not(.separator), list.horizontal row.separator, list.separators.horizontal > row:not(.separator) { border-left: 1px solid #9f958b; } + +listview:not(.horizontal) row.separator, listview.separators:not(.horizontal) > row:not(.separator), list:not(.horizontal) row.separator, list.separators:not(.horizontal) > row:not(.separator) { border-bottom: 1px solid #9f958b; } + +row { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +row { outline: 0 solid transparent; outline-offset: 4px; } + +row:focus:focus-visible { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: -2px; } + +row.activatable.has-open-popup, row.activatable:hover { background-color: rgba(39, 44, 46, 0.05); } + +row.activatable:active { box-shadow: inset 0 2px 2px -2px rgba(0, 0, 0, 0.2); } + +row.activatable:selected:active { box-shadow: inset 0 2px 3px -1px rgba(0, 0, 0, 0.5); } + +row.activatable.has-open-popup:selected, row.activatable:selected:hover { background-color: #1c64bb; } + +row:selected { outline-color: white; } + +columnview > listview > row { padding: 0; } + +columnview > listview > row > cell { padding: 8px 6px; } + +columnview > listview > row > cell:not(:first-child) { border-left: 1px solid transparent; } + +columnview.column-separators > listview > row > cell { border-left-color: #9f958b; } + +columnview.data-table > listview > row > cell { padding-top: 2px; padding-bottom: 2px; } + +treeexpander { border-spacing: 4px; } + +/******************************************************** Data Tables * treeview like tables with individual focusable cells * https://gitlab.gnome.org/GNOME/gtk/-/issues/2929 * */ +columnview row:not(:selected) cell editablelabel:not(.editing):focus-within { outline: 2px solid rgba(27, 106, 203, 0.8); } + +columnview row:not(:selected) cell editablelabel.editing:focus-within { outline: 2px solid #1b6acb; } + +columnview row:not(:selected) cell editablelabel.editing text selection { color: #ffffff; background-color: #1b6acb; } + +/******************************************************* Rich Lists * Large list usually containing lots of widgets * https://gitlab.gnome.org/GNOME/gtk/-/issues/3073 * */ +.rich-list { /* rich lists usually containing other widgets than just labels/text */ } + +.rich-list > row { padding: 8px 12px; min-height: 32px; /* should be tall even when only containing a label */ } + +.rich-list > row > box { border-spacing: 12px; } + +/********************* App Notifications * */ +.app-notification { padding: 10px; border-spacing: 10px; border-radius: 0 0 5px 5px; background-color: rgba(53, 53, 53, 0.7); background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.2), transparent 2px); background-clip: padding-box; } + +.app-notification border { border: none; } + +/************* Expanders * */ +expander { min-width: 16px; min-height: 16px; -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } + +expander:dir(rtl) { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl"); } + +expander:disabled { color: #929495; } + +expander:checked { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +expander-widget { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +expander-widget > box > title { outline: 0 solid transparent; outline-offset: 4px; } + +expander-widget:focus:focus-visible > box > title { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: -2px; } + +expander-widget > box > title { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); border-radius: 5px; } + +expander-widget > box > title:hover > expander { color: #6d7c80; } + +.navigation-sidebar:not(decoration):not(window):drop(active):focus, .navigation-sidebar:not(decoration):not(window):drop(active), placessidebar:not(decoration):not(window):drop(active):focus, placessidebar:not(decoration):not(window):drop(active), stackswitcher:not(decoration):not(window):drop(active):focus, stackswitcher:not(decoration):not(window):drop(active), expander-widget:not(decoration):not(window):drop(active):focus, expander-widget:not(decoration):not(window):drop(active) { box-shadow: none; } + +/************ Calendar * */ +calendar { color: black; border: 1px solid #877b6e; } + +calendar > header { border-bottom: 1px solid #877b6e; } + +calendar > header > button { border: none; box-shadow: none; background: none; border-radius: 0; } + +calendar > header > button:backdrop { background: none; } + +calendar > grid > label.today { box-shadow: inset 0px -2px #877b6e; } + +calendar > grid > label.today:selected { box-shadow: none; } + +calendar > grid > label:focus { outline-color: rgba(27, 106, 203, 0.8); outline-offset: -2px; outline-width: 2px; outline-style: solid; } + +calendar > grid > label.day-number { padding: 4px; } + +calendar > grid > label.day-number:selected { border-radius: 3px; } + +calendar > grid > label.day-number.other-month { color: alpha(currentColor,0.3); } + +/*********** Dialogs * */ +window.dialog.message .titlebar { min-height: 20px; background-image: none; background-color: #fdfdfc; border-style: none; border-top-left-radius: 7px; border-top-right-radius: 7px; } + +window.dialog.message box.dialog-vbox.vertical { border-spacing: 10px; } + +window.dialog.message label.title { font-weight: 800; font-size: 15pt; } + +window.dialog.message.csd.background { border-bottom-left-radius: 9px; border-bottom-right-radius: 9px; } + +window.dialog.message.csd .dialog-action-area button { padding: 10px 14px; border-radius: 0; border-left-style: solid; border-right-style: none; border-bottom-style: none; } + +window.dialog.message.csd .dialog-action-area button:first-child { border-left-style: none; border-bottom-left-radius: 7px; } + +window.dialog.message.csd .dialog-action-area button:last-child { border-bottom-right-radius: 7px; } + +filechooser .dialog-action-box { border-top: 1px solid #877b6e; } + +filechooser #pathbarbox { border-bottom: 1px solid #fdfdfc; } + +filechooserbutton > button > box { border-spacing: 6px; } + +filechooserbutton:drop(active) { box-shadow: none; border-color: transparent; } + +/*********** Sidebar * */ +.sidebar { background-color: #fefefe; } + +.sidebar:not(separator):dir(ltr), .sidebar.left:not(separator), .sidebar.left:not(separator):dir(rtl) { border-right: 1px solid #877b6e; border-left-style: none; } + +.sidebar:not(separator):dir(rtl), .sidebar.right:not(separator) { border-left: 1px solid #877b6e; border-right-style: none; } + +.sidebar listview.view, .sidebar list { background-color: transparent; } + +paned .sidebar.left, paned .sidebar.right, paned .sidebar.left:dir(rtl), paned .sidebar:dir(rtl), paned .sidebar:dir(ltr), paned .sidebar { border-style: none; } + +stacksidebar list.separators:not(.horizontal) > row:not(.separator) { border-bottom: none; } + +stacksidebar row { padding: 10px 4px; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +stacksidebar row { outline: 0 solid transparent; outline-offset: 4px; } + +stacksidebar row:focus:focus-visible { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: -2px; } + +stacksidebar row > label { padding-left: 6px; padding-right: 6px; } + +stacksidebar row.needs-attention > label { background-size: 6px 6px, 0 0; } + +stacksidebar row:selected { background-color: #e6e3e0; border-radius: 5px; color: #272c2e; } + +stacksidebar row:selected:hover:dir(ltr), stacksidebar row:selected:hover:dir(rtl) { background-color: #dad6d2; } + +stacksidebar row.activatable:active, stacksidebar row.activatable:selected:active { box-shadow: none; } + +separator.sidebar { background-color: #877b6e; } + +/********************** Navigation Sidebar * */ +.navigation-sidebar { padding: 5px 0; } + +.navigation-sidebar > separator { margin: 5px; } + +.navigation-sidebar > row { min-height: 36px; padding: 0 8px; border-radius: 5px; margin: 0 5px 2px; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +.navigation-sidebar > row { outline: 0 solid transparent; outline-offset: 4px; } + +.navigation-sidebar > row:focus-visible:focus-within { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: -2px; } + +.navigation-sidebar > row:hover { background-color: #dad6d2; } + +.navigation-sidebar > row:selected { background-color: #e6e3e0; color: inherit; } + +.navigation-sidebar > row:selected:hover { background-color: #dad6d2; } + +.navigation-sidebar > row:disabled { color: #929495; } + +/**************** File chooser * */ +row image.sidebar-icon { opacity: 0.7; } + +/* this should be more generic, only using .navigation-sidebar https://gitlab.gnome.org/GNOME/gtk/-/issues/2929 */ +placessidebar .navigation-sidebar > row { padding: 0; } + +placessidebar .navigation-sidebar > row > revealer { padding: 0 14px; } + +placessidebar .navigation-sidebar > row image.sidebar-icon:dir(ltr) { padding-right: 8px; } + +placessidebar .navigation-sidebar > row image.sidebar-icon:dir(rtl) { padding-left: 8px; } + +placessidebar .navigation-sidebar > row label.sidebar-label:dir(ltr) { padding-right: 2px; } + +placessidebar .navigation-sidebar > row label.sidebar-label:dir(rtl) { padding-left: 2px; } + +button.sidebar-button { min-height: 26px; min-width: 26px; margin-top: 3px; margin-bottom: 3px; padding: 0; border-radius: 100%; } + +placessidebar .navigation-sidebar > row:selected:active { box-shadow: none; } + +placessidebar .navigation-sidebar > row.sidebar-placeholder-row { padding: 0 8px; min-height: 2px; background-image: image(#2ec27e); background-clip: content-box; } + +placessidebar .navigation-sidebar > row.sidebar-new-bookmark-row { color: #1b6acb; } + +placessidebar .navigation-sidebar > row:drop(active):not(:disabled) { color: #2ec27e; box-shadow: inset 0 1px #2ec27e, inset 0 -1px #2ec27e; } + +placessidebar .navigation-sidebar > row:drop(active):not(:disabled):selected { color: #ffffff; background-color: #2ec27e; } + +placesview .server-list-button > image { transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -gtk-icon-transform: rotate(0turn); } + +placesview .server-list-button:checked > image { transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -gtk-icon-transform: rotate(-0.5turn); } + +placesview > actionbar > revealer > box > box { border-spacing: 6px; } + +/********* Paned * */ +paned > separator { min-width: 1px; min-height: 1px; -gtk-icon-source: none; border-style: none; background-color: transparent; background-image: image(#877b6e); background-size: 1px 1px; } + +paned > separator:selected { background-image: image(#1b6acb); } + +paned > separator.wide { min-width: 5px; min-height: 5px; background-color: #fdfdfc; background-image: image(#877b6e), image(#877b6e); background-size: 1px 1px, 1px 1px; } + +paned.horizontal > separator { background-repeat: repeat-y; } + +paned.horizontal > separator:dir(ltr) { margin: 0 -8px 0 0; padding: 0 8px 0 0; background-position: left; } + +paned.horizontal > separator:dir(rtl) { margin: 0 0 0 -8px; padding: 0 0 0 8px; background-position: right; } + +paned.horizontal > separator.wide { margin: 0; padding: 0; background-repeat: repeat-y, repeat-y; background-position: left, right; } + +paned.vertical > separator { margin: 0 0 -8px 0; padding: 0 0 8px 0; background-repeat: repeat-x; background-position: top; } + +paned.vertical > separator.wide { margin: 0; padding: 0; background-repeat: repeat-x, repeat-x; background-position: bottom, top; } + +/************** GtkVideo * */ +video { background: black; } + +video image.osd { min-width: 64px; min-height: 64px; border-radius: 32px; } + +/************ Tooltips * */ +tooltip { padding: 6px 10px; border-radius: 8px; box-shadow: none; } + +tooltip.background { background-color: rgba(0, 0, 0, 0.8); background-clip: padding-box; border: 1px solid rgba(255, 255, 255, 0.1); color: white; } + +tooltip > box { border-spacing: 6px; } + +/***************** Color Chooser * */ +colorswatch { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +colorswatch { outline: 0 solid transparent; outline-offset: 6px; } + +colorswatch:focus:focus-visible { outline-color: rgba(27, 106, 203, 0.8); outline-width: 4px; outline-offset: -2px; } + +colorswatch:drop(active), colorswatch { border-style: none; } + +colorswatch.top { border-top-left-radius: 5.5px; border-top-right-radius: 5.5px; } + +colorswatch.top > overlay { border-top-left-radius: 5px; border-top-right-radius: 5px; } + +colorswatch.bottom { border-bottom-left-radius: 5.5px; border-bottom-right-radius: 5.5px; } + +colorswatch.bottom > overlay { border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } + +colorswatch.left, colorswatch:first-child:not(.top) { border-top-left-radius: 5.5px; border-bottom-left-radius: 5.5px; } + +colorswatch.left > overlay, colorswatch:first-child:not(.top) > overlay { border-top-left-radius: 5px; border-bottom-left-radius: 5px; } + +colorswatch.right, colorswatch:last-child:not(.bottom) { border-top-right-radius: 5.5px; border-bottom-right-radius: 5.5px; } + +colorswatch.right > overlay, colorswatch:last-child:not(.bottom) > overlay { border-top-right-radius: 5px; border-bottom-right-radius: 5px; } + +colorswatch.dark > overlay { color: white; } + +colorswatch.dark.activatable:hover > overlay { border-color: rgba(0, 0, 0, 0.8); } + +colorswatch.light > overlay { color: black; } + +colorswatch.light.activatable:hover > overlay { border-color: rgba(0, 0, 0, 0.5); } + +colorswatch:drop(active) { box-shadow: none; } + +colorswatch.light:drop(active) > overlay { border-color: #2ec27e; box-shadow: inset 0 0 0 2px #27a56b, inset 0 0 0 1px #2ec27e; } + +colorswatch.dark:drop(active) > overlay { border-color: #2ec27e; box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.3), inset 0 0 0 1px #2ec27e; } + +colorswatch > overlay { border: 1px solid rgba(0, 0, 0, 0.3); } + +colorswatch.activatable:hover > overlay { box-shadow: inset 0 1px rgba(255, 255, 255, 0.4), inset 0 -1px rgba(0, 0, 0, 0.2); } + +colorswatch#add-color-button { border-radius: 5px 0 0 5px; } + +colorswatch#add-color-button:only-child { border-radius: 5px; } + +colorswatch#add-color-button > overlay { color: #272c2e; outline-color: rgba(27, 106, 203, 0.8); border-color: #877b6e; background-image: linear-gradient(to top, #fafaf9 2px, white); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +colorswatch#add-color-button.activatable:hover > overlay { color: #272c2e; border-color: #877b6e; background-image: linear-gradient(to top, #dad6d2, #edebe9 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +colorswatch:disabled { opacity: 0.5; } + +colorswatch:disabled > overlay { border-color: rgba(0, 0, 0, 0.6); box-shadow: none; } + +row:selected colorswatch { box-shadow: 0 0 0 2px #ffffff; } + +colorswatch#editor-color-sample { border-radius: 4px; } + +colorswatch#editor-color-sample > overlay { border-radius: 4.5px; } + +plane { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +plane { outline: 0 solid transparent; outline-offset: 6px; } + +plane:focus:focus-visible { outline-color: rgba(27, 106, 203, 0.8); outline-width: 2px; outline-offset: 2px; } + +colorchooser .popover.osd { border-radius: 5px; } + +/******** Misc * */ +.content-view { background-color: #edebe9; } + +.content-view:hover { -gtk-icon-filter: brightness(1.2); } + +.content-view .tile { margin: 2px; background-color: transparent; border-radius: 0; padding: 0; } + +.content-view .tile:active, .content-view .tile:selected { background-color: transparent; } + +.content-view .tile:disabled { background-color: transparent; } + +.osd .scale-popup button.flat { border-style: none; border-radius: 5px; } + +.scale-popup button:hover { background-color: rgba(39, 44, 46, 0.1); border-radius: 5px; } + +/********************** Window Decorations * */ +window { border-width: 0px; } + +window.csd { box-shadow: 0 3px 9px 1px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(0, 0, 0, 0.23); margin: 0px; border-radius: 8px 8px 0 0; } + +window.csd:backdrop { box-shadow: 0 3px 9px 1px transparent, 0 2px 6px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.18); transition: 200ms ease-out; } + +window.csd.popup { border-radius: 5px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.13); } + +window.csd.dialog.message { border-radius: 8px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.13); } + +window.solid-csd { margin: 0; padding: 4px; border: solid 1px #877b6e; border-radius: 0; box-shadow: inset 0 0 0 4px #877b6e, inset 0 0 0 3px white, inset 0 1px rgba(255, 255, 255, 0.8); } + +window.solid-csd:backdrop { box-shadow: inset 0 0 0 4px #877b6e, inset 0 0 0 3px #f6f5f4, inset 0 1px rgba(255, 255, 255, 0.8); } + +window.maximized, window.fullscreen { border-radius: 0; box-shadow: none; } + +window.tiled, window.tiled-top, window.tiled-left, window.tiled-right, window.tiled-bottom { border-radius: 0; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18), 0 0 0 20px transparent; } + +window:backdrop { box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18), 0 0 0 20px transparent; } + +window.popup { box-shadow: none; } + +window.ssd { box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.23); } + +tooltip.csd { border-radius: 5px; box-shadow: none; } + +.view:selected:focus, .view:selected, textview > text:selected:focus, textview > text:selected, textview > text > selection:focus, textview > text > selection, iconview:selected:focus, iconview:selected, flowbox > flowboxchild:selected, gridview > child:selected, entry > text > selection, modelbutton.flat:selected, spinbutton:not(.vertical) > text > selection, spinbutton.vertical > text > text > selection, spinbutton.vertical > text > selection, columnview.view:selected:focus, columnview.view:selected, treeview.view:selected:focus, treeview.view:selected, row:selected, calendar > grid > label.day-number:selected { background-color: #1b6acb; } + +label:selected, .view:selected:focus, .view:selected, textview > text:selected:focus, textview > text:selected, textview > text > selection:focus, textview > text > selection, iconview:selected:focus, iconview:selected, flowbox > flowboxchild:selected, gridview > child:selected, entry > text > selection, modelbutton.flat:selected, spinbutton:not(.vertical) > text > selection, spinbutton.vertical > text > text > selection, spinbutton.vertical > text > selection, columnview.view:selected:focus, columnview.view:selected, treeview.view:selected:focus, treeview.view:selected, row:selected, calendar > grid > label.day-number:selected { color: #ffffff; } + +label:disabled > selection, label:disabled:selected, .view:disabled:selected, textview > text:disabled:selected:focus, textview > text:disabled:selected, textview > text > selection:disabled, iconview:disabled:selected:focus, iconview:disabled:selected, flowbox > flowboxchild:disabled:selected, gridview > child:disabled:selected, entry > text > selection:disabled, modelbutton.flat:disabled:selected, spinbutton:not(.vertical) > text > selection:disabled, spinbutton.vertical > text > text > selection:disabled, spinbutton.vertical > text > selection:disabled, columnview.view:disabled:selected, treeview.view:disabled:selected, row:disabled:selected, calendar > grid > label.day-number:disabled:selected { color: #8db5e5; } + +.monospace { font-family: monospace; } + +/********************** Touch Copy & Paste * */ +cursor-handle { background-color: transparent; background-image: none; box-shadow: none; border-style: none; min-width: 20px; min-height: 24px; padding-left: 20px; padding-right: 20px; padding-top: 24px; padding-bottom: 24px; } + +cursor-handle.top:dir(ltr), cursor-handle.bottom:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/text-select-start.png"), url("assets-hc/text-select-start@2.png")); } + +cursor-handle.bottom:dir(ltr), cursor-handle.top:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/text-select-end.png"), url("assets-hc/text-select-end@2.png")); } + +cursor-handle.insertion-cursor:dir(ltr), cursor-handle.insertion-cursor:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-above.png"), url("assets-hc/slider-horz-scale-has-marks-above@2.png")); } + +cursor-handle.top:hover:dir(ltr), cursor-handle.bottom:hover:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/text-select-start-hover.png"), url("assets-hc/text-select-start-hover@2.png")); } + +cursor-handle.bottom:hover:dir(ltr), cursor-handle.top:hover:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/text-select-end-hover.png"), url("assets-hc/text-select-end-hover@2.png")); } + +cursor-handle.insertion-cursor:hover:dir(ltr), cursor-handle.insertion-cursor:hover:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-above-hover.png"), url("assets-hc/slider-horz-scale-has-marks-above-hover@2.png")); } + +cursor-handle.top:active:dir(ltr), cursor-handle.bottom:active:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/text-select-start-active.png"), url("assets-hc/text-select-start-active@2.png")); } + +cursor-handle.bottom:active:dir(ltr), cursor-handle.top:active:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/text-select-end-active.png"), url("assets-hc/text-select-end-active@2.png")); } + +cursor-handle.insertion-cursor:active:dir(ltr), cursor-handle.insertion-cursor:active:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets-hc/slider-horz-scale-has-marks-above-active.png"), url("assets-hc/slider-horz-scale-has-marks-above-active@2.png")); } + +shortcuts-section { margin: 20px; } + +.shortcuts-search-results { margin: 20px; border-spacing: 24px; } + +shortcut { border-spacing: 6px; } + +shortcut > .keycap { min-width: 20px; min-height: 25px; margin-top: 2px; padding-bottom: 3px; padding-left: 6px; padding-right: 6px; color: #272c2e; background-color: #ffffff; border: 1px solid; border-color: #c2bcb5; border-radius: 5px; box-shadow: inset 0 -3px #fdfdfd; font-size: smaller; } + +:not(decoration):not(window):drop(active):focus, :not(decoration):not(window):drop(active) { border-color: #2ec27e; box-shadow: inset 0 0 0 1px #2ec27e; caret-color: #2ec27e; } + +stackswitcher > button.text-button { min-width: 100px; } + +stackswitcher.circular { border-spacing: 12px; } + +stackswitcher.circular > button.circular, stackswitcher.circular > button.text-button.circular { min-width: 32px; min-height: 32px; padding: 0; } + +/************* App Icons * */ +/* Outline for low res icons */ +.lowres-icon { -gtk-icon-shadow: 0 -1px rgba(0, 0, 0, 0.05), 1px 0 rgba(0, 0, 0, 0.1), 0 1px rgba(0, 0, 0, 0.3), -1px 0 rgba(0, 0, 0, 0.1); } + +/* Drapshadow for large icons */ +.icon-dropshadow { -gtk-icon-shadow: 0 1px 12px rgba(0, 0, 0, 0.05), 0 -1px rgba(0, 0, 0, 0.05), 1px 0 rgba(0, 0, 0, 0.1), 0 1px rgba(0, 0, 0, 0.3), -1px 0 rgba(0, 0, 0, 0.1); } + +/********* Emoji * */ +popover.emoji-picker > contents { padding: 0; } + +.emoji-searchbar { padding: 6px; border-spacing: 6px; border-bottom: 1px solid #877b6e; } + +.emoji-toolbar { padding: 6px; border-spacing: 6px; border-top: 1px solid #877b6e; } + +button.emoji-section { border-color: transparent; border-width: 3px; border-style: none none solid; border-radius: 0; padding: 3px 0 0; min-width: 32px; min-height: 28px; /* reset props inherited from the button style */ background: none; box-shadow: none; text-shadow: none; } + +button.emoji-section:hover { border-color: #877b6e; } + +button.emoji-section:checked { border-color: #1b6acb; } + +popover.emoji-picker emoji { font-size: x-large; padding: 6px; border-radius: 6px; } + +popover.emoji-picker emoji:focus, popover.emoji-picker emoji:hover { background: #1b6acb; } + +emoji-completion-row > box { border-spacing: 10px; padding: 2px 10px; } + +emoji-completion-row:focus, emoji-completion-row:hover { background-color: #1b6acb; color: #ffffff; } + +emoji-completion-row emoji:focus, emoji-completion-row emoji:hover { background-color: #e6e3e0; } + +popover.entry-completion > contents { padding: 0; } + +statusbar { padding: 6px 10px 6px 10px; } + +menubutton > button > box { border-spacing: 6px; } + +menubutton arrow { min-height: 16px; min-width: 16px; } + +menubutton arrow.none { -gtk-icon-source: -gtk-icontheme("open-menu-symbolic"); } + +menubutton arrow.down { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +menubutton arrow.up { -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); } + +menubutton arrow.left { -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); } + +menubutton arrow.right { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } diff --cc gtk/theme/Default/Default-light.css index 43d1f46aef,0000000000..9b4d610ef8 mode 100644,000000..100644 --- a/gtk/theme/Default/Default-light.css +++ b/gtk/theme/Default/Default-light.css @@@ -1,1870 -1,0 +1,1860 @@@ +/*************************** Check and Radio buttons * */ +/*************** Base States * */ +.background { color: #2e3436; background-color: #f6f5f4; } + +.background:backdrop { text-shadow: none; -gtk-icon-shadow: none; } + +dnd { color: #2e3436; } + +.normal-icons { -gtk-icon-size: 16px; } + +.large-icons { -gtk-icon-size: 32px; } + +image:disabled { -gtk-icon-filter: opacity(0.5); } + +.view, iconview, textview > text { color: black; background-color: #ffffff; } + +.view:disabled, iconview:disabled, textview > text:disabled { color: #929595; background-color: #faf9f8; } + +.view:selected:focus, iconview:selected:focus, .view:selected, iconview:selected, textview > text:selected:focus, textview > text:selected { border-radius: 3px; } + +textview:drop(active) { caret-color: #2ec27e; } + +textview > border { background-color: #fbfafa; } + +iconview { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +iconview { outline: 0 solid transparent; outline-offset: 4px; } + +iconview:focus:focus-visible { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: -2px; } + +iconview:drop(active) { box-shadow: none; } + +iconview > dndtarget:drop(active) { border-style: solid; border-width: 1px; border-color: #185fb4; } + +rubberband, .content-view > rubberband, columnview.view > rubberband, treeview.view > rubberband, gridview > rubberband, flowbox > rubberband { border: 1px solid #1b6acb; background-color: rgba(27, 106, 203, 0.2); } + +flowbox > flowboxchild { padding: 3px; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +flowbox > flowboxchild { outline: 0 solid transparent; outline-offset: 4px; } + +flowbox > flowboxchild:focus:focus-visible { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: -2px; } + +flowbox > flowboxchild:selected { outline-color: rgba(255, 255, 255, 0.8); } + +gridview > child { padding: 3px; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +gridview > child { outline: 0 solid transparent; outline-offset: 4px; } + +gridview > child:focus:focus-visible { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: -2px; } + +gridview > child:selected { outline-color: rgba(255, 255, 255, 0.8); } + +gridview > child box { border-spacing: 8px; margin: 12px; } + +coverflow cover { color: black; background-color: #ffffff; border: 1px solid black; } + +label { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +label { outline: 0 solid transparent; outline-offset: 4px; } + +label:focus:focus-visible { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: -2px; } + +label > selection { background-color: #3584e4; color: #ffffff; } + +label:disabled { color: #929595; } + +button label:disabled { color: inherit; } + +label.error { color: #cc0000; } + +label.error:disabled { color: rgba(204, 0, 0, 0.5); } + +.dim-label, .titlebar:not(headerbar) .subtitle, headerbar .subtitle, spinbutton.vertical > text > text > placeholder, spinbutton:not(.vertical) > text > placeholder, entry > text > placeholder, label.separator { opacity: 0.55; text-shadow: none; } + +window.assistant .sidebar { padding: 5px; border-top: 1px solid #cdc7c2; } + +window.assistant.csd .sidebar { border-top-style: none; } + +window.assistant .sidebar > label { padding: 6px 12px; } + +window.assistant .sidebar > label.highlight { background-color: #e8e6e3; border-radius: 5px; } + +window.aboutdialog image.large-icons { -gtk-icon-size: 128px; } + +.osd .scale-popup, .app-notification, .osd popover.background > arrow, .osd popover.background > contents, popover.background.touch-selection > arrow, popover.background.touch-selection > contents, popover.background.magnifier > arrow, popover.background.magnifier > contents, .osd { color: #eeeeec; border: none; background-color: rgba(53, 53, 53, 0.7); background-clip: padding-box; -gtk-icon-shadow: 0 1px black; } + +/********************* Spinner Animation * */ +@keyframes spin { to { transform: rotate(1turn); } } + +spinner { background: none; opacity: 0; -gtk-icon-source: -gtk-icontheme("process-working-symbolic"); } + +spinner:checked { opacity: 1; animation: spin 1s linear infinite; } + +spinner:checked:disabled { opacity: 0.5; } + +/********************** General Typography * */ +.large-title { font-weight: 300; font-size: 24pt; } + +.title-1 { font-weight: 800; font-size: 20pt; } + +.title-2 { font-weight: 800; font-size: 15pt; } + +.title-3 { font-weight: 700; font-size: 15pt; } + +.title-4 { font-weight: 700; font-size: 13pt; } + +.heading { font-weight: 700; font-size: 11pt; } + +.body { font-weight: 400; font-size: 11pt; } + +.caption-heading { font-weight: 700; font-size: 9pt; } + +.caption { font-weight: 400; font-size: 9pt; } + +/**************** Text Entries * */ +spinbutton.vertical > text, spinbutton:not(.vertical), entry { min-height: 32px; padding-left: 8px; padding-right: 8px; border: 1px solid; border-radius: 5px; border-spacing: 6px; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); color: black; border-color: #cdc7c2; background-color: #ffffff; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +spinbutton.vertical > text, spinbutton:not(.vertical), entry { outline: 0 solid transparent; outline-offset: 4px; } + +spinbutton.vertical > text:focus-within, spinbutton:focus-within:not(.vertical), entry:focus-within { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: -2px; } + +spinbutton.vertical > text > image.left, spinbutton:not(.vertical) > image.left, entry > image.left { margin-right: 6px; } + +spinbutton.vertical > text > image.right, spinbutton:not(.vertical) > image.right, entry > image.right { margin-left: 6px; } + +spinbutton.vertical > text > text > block-cursor, spinbutton:not(.vertical) > text > block-cursor, entry > text > block-cursor { color: #ffffff; background-color: black; } + +spinbutton.vertical > text.flat, spinbutton.flat:not(.vertical), entry.flat:focus-within, entry.flat:backdrop, entry.flat:disabled, entry.flat { min-height: 0; padding: 2px; background-color: transparent; border-color: transparent; border-radius: 0; } + +spinbutton.vertical > text:focus-within > placeholder, spinbutton:focus-within:not(.vertical) > placeholder, entry:focus-within > placeholder { opacity: 0; /* We hide placeholders on focus */ } + +spinbutton.vertical > text:disabled, spinbutton:disabled:not(.vertical), entry:disabled { color: #929595; border-color: #cdc7c2; background-color: #faf9f8; } + +spinbutton.vertical > text.error, spinbutton.error:not(.vertical), entry.error { color: #cc0000; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +spinbutton.vertical > text.error, spinbutton.error:not(.vertical), entry.error { outline: 0 solid transparent; outline-offset: 4px; } + +spinbutton.vertical > text.error:focus-within, spinbutton.error:focus-within:not(.vertical), entry.error:focus-within { outline-color: rgba(204, 0, 0, 0.5); outline-width: 2px; outline-offset: -2px; } + +spinbutton.vertical > text.error > selection, spinbutton.error:not(.vertical) > selection, entry.error > selection { background-color: #cc0000; } + +spinbutton.vertical > text.warning, spinbutton.warning:not(.vertical), entry.warning { color: #f57900; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +spinbutton.vertical > text.warning, spinbutton.warning:not(.vertical), entry.warning { outline: 0 solid transparent; outline-offset: 4px; } + +spinbutton.vertical > text.warning:focus-within, spinbutton.warning:focus-within:not(.vertical), entry.warning:focus-within { outline-color: rgba(245, 121, 0, 0.5); outline-width: 2px; outline-offset: -2px; } + +spinbutton.vertical > text.warning > selection, spinbutton.warning:not(.vertical) > selection, entry.warning > selection { background-color: #f57900; } + +spinbutton.vertical > text > image, spinbutton:not(.vertical) > image, entry > image { color: #585d5e; } + +spinbutton.vertical > text > image:hover, spinbutton:not(.vertical) > image:hover, entry > image:hover { color: #2e3436; } + +spinbutton.vertical > text > image:active, spinbutton:not(.vertical) > image:active, entry > image:active { color: #3584e4; } + +spinbutton.vertical > text.password image.caps-lock-indicator, spinbutton.password:not(.vertical) image.caps-lock-indicator, entry.password image.caps-lock-indicator { color: #a7aaaa; } + +spinbutton.vertical > text:drop(active), spinbutton:drop(active):not(.vertical), entry:drop(active):focus-within, entry:drop(active) { border-color: #2ec27e; box-shadow: inset 0 0 0 1px #2ec27e; } + +.osd spinbutton.vertical > text, .osd spinbutton:not(.vertical), .osd entry { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: rgba(0, 0, 0, 0.5); background-clip: padding-box; box-shadow: none; -gtk-icon-shadow: 0 1px black; } + +.osd spinbutton.vertical > text:focus-within, .osd spinbutton:focus-within:not(.vertical), .osd entry:focus-within { color: white; border-color: #3584e4; background-color: rgba(0, 0, 0, 0.5); background-clip: padding-box; } + +.osd spinbutton.vertical > text:disabled, .osd spinbutton:disabled:not(.vertical), .osd entry:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: rgba(71, 71, 71, 0.5); background-clip: padding-box; } + +spinbutton.vertical > text > progress, spinbutton:not(.vertical) > progress, entry > progress { margin-bottom: 2px; } + +spinbutton.vertical > text progress > trough > progress, spinbutton:not(.vertical) progress > trough > progress, entry progress > trough > progress { background-color: transparent; background-image: none; border-radius: 0; border-width: 0 0 2px; border-color: #3584e4; border-style: solid; box-shadow: none; } + +spinbutton.vertical.linked:not(.vertical) > text:drop(active) + text, spinbutton.vertical.linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + text, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + spinbutton:not(.vertical), .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + spinbutton:not(.vertical), spinbutton.vertical.linked:not(.vertical) > text:drop(active) + button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + menubutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + menubutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + dropdown > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + dropdown > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + colorbutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + colorbutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + fontbutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + fontbutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + filechooserbutton > button, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + filechooserbutton > button, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + combobox > box > button.combo, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + combobox > box > button.combo, spinbutton.vertical.linked:not(.vertical) > text:drop(active) + entry, .linked:not(.vertical) > spinbutton:drop(active):not(.vertical) + entry, .linked:not(.vertical) > entry:drop(active) + button, .linked:not(.vertical) > entry:drop(active) + menubutton > button, .linked:not(.vertical) > entry:drop(active) + dropdown > button, .linked:not(.vertical) > entry:drop(active) + colorbutton > button, .linked:not(.vertical) > entry:drop(active) + fontbutton > button, .linked:not(.vertical) > entry:drop(active) + filechooserbutton > button, .linked:not(.vertical) > entry:drop(active) + combobox > box > button.combo, spinbutton.vertical.linked:not(.vertical) > entry:drop(active) + text, .linked:not(.vertical) > entry:drop(active) + spinbutton:not(.vertical), .linked:not(.vertical) > entry:drop(active) + entry { border-left-color: #2ec27e; } + +spinbutton.vertical.linked > text:not(:disabled) + entry:not(:disabled), .linked.vertical > spinbutton:not(:disabled):not(.vertical) + entry:not(:disabled), spinbutton.vertical.linked > text:not(:disabled) + text:not(:disabled), spinbutton.vertical.linked > spinbutton:not(:disabled):not(.vertical) + text:not(:disabled), spinbutton.vertical.linked > text:not(:disabled) + spinbutton:not(:disabled):not(.vertical), .linked.vertical > spinbutton:not(:disabled):not(.vertical) + spinbutton:not(:disabled):not(.vertical), .linked.vertical > entry:not(:disabled) + entry:not(:disabled), spinbutton.vertical.linked > entry:not(:disabled) + text:not(:disabled), .linked.vertical > entry:not(:disabled) + spinbutton:not(:disabled):not(.vertical) { border-top-color: #f0eeed; } + +spinbutton.vertical.linked > text:disabled + text:disabled, spinbutton.vertical.linked > spinbutton:disabled:not(.vertical) + text:disabled, spinbutton.vertical.linked > text:disabled + spinbutton:disabled:not(.vertical), .linked.vertical > spinbutton:disabled:not(.vertical) + spinbutton:disabled:not(.vertical), spinbutton.vertical.linked > text:disabled + entry:disabled, .linked.vertical > spinbutton:disabled:not(.vertical) + entry:disabled, spinbutton.vertical.linked > entry:disabled + text:disabled, .linked.vertical > entry:disabled + spinbutton:disabled:not(.vertical), .linked.vertical > entry:disabled + entry:disabled { border-top-color: #f0eeed; } + +spinbutton.vertical.linked > text + text:drop(active):not(:only-child), spinbutton.vertical.linked > spinbutton:not(.vertical) + text:drop(active):not(:only-child), spinbutton.vertical.linked > text + spinbutton:drop(active):not(:only-child):not(.vertical), .linked.vertical > spinbutton:not(.vertical) + spinbutton:drop(active):not(:only-child):not(.vertical), spinbutton.vertical.linked > text + entry:drop(active):not(:only-child), .linked.vertical > spinbutton:not(.vertical) + entry:drop(active):not(:only-child), spinbutton.vertical.linked > entry + text:drop(active):not(:only-child), .linked.vertical > entry + spinbutton:drop(active):not(:only-child):not(.vertical), .linked.vertical > entry + entry:drop(active):not(:only-child) { border-top-color: #2ec27e; } + +spinbutton.vertical.linked > text:drop(active):not(:only-child) + text, spinbutton.vertical.linked > spinbutton:drop(active):not(:only-child):not(.vertical) + text, spinbutton.vertical.linked > text:drop(active):not(:only-child) + spinbutton:not(.vertical), .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + spinbutton:not(.vertical), spinbutton.vertical.linked > text:drop(active):not(:only-child) + entry, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + entry, spinbutton.vertical.linked > text:drop(active):not(:only-child) + button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + menubutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + menubutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + dropdown > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + dropdown > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + colorbutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + colorbutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + fontbutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + fontbutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + filechooserbutton > button, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + filechooserbutton > button, spinbutton.vertical.linked > text:drop(active):not(:only-child) + combobox > box > button.combo, .linked.vertical > spinbutton:drop(active):not(:only-child):not(.vertical) + combobox > box > button.combo, spinbutton.vertical.linked > entry:drop(active):not(:only-child) + text, .linked.vertical > entry:drop(active):not(:only-child) + spinbutton:not(.vertical), .linked.vertical > entry:drop(active):not(:only-child) + entry, .linked.vertical > entry:drop(active):not(:only-child) + button, .linked.vertical > entry:drop(active):not(:only-child) + menubutton > button, .linked.vertical > entry:drop(active):not(:only-child) + dropdown > button, .linked.vertical > entry:drop(active):not(:only-child) + colorbutton > button, .linked.vertical > entry:drop(active):not(:only-child) + fontbutton > button, .linked.vertical > entry:drop(active):not(:only-child) + filechooserbutton > button, .linked.vertical > entry:drop(active):not(:only-child) + combobox > box > button.combo { border-top-color: #2ec27e; } + +spinbutton.vertical > text.error, spinbutton.error:not(.vertical), entry.error { color: #cc0000; } + +treeview entry:focus-within:dir(rtl), treeview entry:focus-within:dir(ltr) { background-color: #ffffff; transition-property: color, background; } + +treeview entry.flat, treeview entry { border-radius: 0; background-image: none; background-color: #ffffff; } + +treeview entry.flat:focus-within, treeview entry:focus-within { border-color: #3584e4; } + +/******************* Editable Labels * */ +editablelabel > stack > text { color: black; border-color: #cdc7c2; background-color: #ffffff; } + +/*********** Buttons * */ +@keyframes needs_attention { from { background-image: radial-gradient(farthest-side, #3584e4 0%, rgba(53, 132, 228, 0) 0%); } + to { background-image: radial-gradient(farthest-side, #3584e4 95%, rgba(53, 132, 228, 0)); } } + +notebook > header > tabs > arrow, windowcontrols button, button { min-height: 24px; min-width: 16px; padding: 4px 9px; border: 1px solid; border-radius: 5px; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); color: #2e3436; outline-color: rgba(53, 132, 228, 0.5); border-color: #cdc7c2; background-image: linear-gradient(to top, #f6f5f4 2px, #fbfafa); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +notebook > header > tabs > arrow, windowcontrols button, button { outline: 0 solid transparent; outline-offset: 4px; } + +notebook > header > tabs > arrow:focus:focus-visible, button:focus:focus-visible { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: -2px; } + +notebook > header > tabs > arrow:hover, button:hover { color: #2e3436; border-color: #cdc7c2; background-image: linear-gradient(to top, #d6d1cd, #e8e6e3 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); -gtk-icon-filter: brightness(1.2); } + +notebook > header > tabs > arrow.keyboard-activating, notebook > header > tabs > arrow:active, notebook > header > tabs > arrow:checked, button.keyboard-activating, button:active, button:checked { color: #2e3436; border-color: #cdc7c2; background-image: image(#dad6d2); box-shadow: none; transition-duration: 50ms; } + +notebook > header > tabs > arrow:checked:hover, button:checked:hover { color: #2e3436; border-color: #cdc7c2; background-image: image(#d1ccc7); box-shadow: none; } + +notebook > header > tabs > arrow:checked:active, button:checked:active { color: #2e3436; border-color: #cdc7c2; background-image: image(#c8c2bc); box-shadow: none; } + +notebook > header > tabs > arrow:backdrop, button.flat:backdrop, button:backdrop { color: #929595; border-color: #d5d0cc; background-image: image(#f6f5f4); box-shadow: none; transition: 200ms ease-out; } + +notebook > header > tabs > arrow:backdrop:not(:disabled), button.flat:backdrop:not(:disabled), button:backdrop:not(:disabled) { -gtk-icon-filter: none; } + +notebook > header > tabs > arrow:backdrop:active, notebook > header > tabs > arrow:backdrop:checked, button.flat:backdrop:active, button.flat:backdrop:checked, button:backdrop:active, button:backdrop:checked { color: #929595; border-color: #d5d0cc; background-image: image(#e9e9e3); box-shadow: none; } + +notebook > header > tabs > arrow:backdrop:disabled, button.flat:backdrop:disabled, button:backdrop:disabled { color: #d4cfca; border-color: #d5d0cc; background-image: image(#faf9f8); box-shadow: none; } + +notebook > header > tabs > arrow:backdrop:disabled:active, notebook > header > tabs > arrow:backdrop:disabled:checked, button.flat:backdrop:disabled:active, button.flat:backdrop:disabled:checked, button:backdrop:disabled:active, button:backdrop:disabled:checked { color: #d4cfca; border-color: #d5d0cc; background-image: image(#e9e9e3); box-shadow: none; } + +notebook > header > tabs > arrow:disabled, button:disabled { color: #929595; border-color: #d5d0cc; background-image: image(#faf9f8); -gtk-icon-filter: opacity(0.5); } + +notebook > header > tabs > arrow:disabled:active, notebook > header > tabs > arrow:disabled:checked, button:disabled:active, button:disabled:checked { color: #929595; border-color: #d5d0cc; background-image: image(#e9e9e3); box-shadow: none; } + - button.sidebar-button, notebook > header > tabs > arrow, windowcontrols button, notebook > header > tabs > arrow.flat, button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; transition: none; } ++button.sidebar-button, notebook > header > tabs > arrow, windowcontrols button, .toolbar button, notebook > header > tabs > arrow.flat, button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; transition: none; } + - button.sidebar-button:hover, notebook > header > tabs > arrow:hover, windowcontrols button:hover, button.flat:hover { border-color: transparent; background-image: none; box-shadow: none; background-color: #dad6d2; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-duration: 500ms; } ++button.sidebar-button:hover, notebook > header > tabs > arrow:hover, windowcontrols button:hover, .toolbar button:hover, button.flat:hover { border-color: transparent; background-image: none; box-shadow: none; background-color: #dad6d2; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-duration: 500ms; } + - button.keyboard-activating.sidebar-button, notebook > header > tabs > arrow.keyboard-activating, windowcontrols button.keyboard-activating, button.sidebar-button:active, notebook > header > tabs > arrow:active, windowcontrols button:active, button.sidebar-button:checked, notebook > header > tabs > arrow:checked, windowcontrols button:checked, button.flat.keyboard-activating, button.flat:active, button.flat:checked { border-color: transparent; background-image: none; box-shadow: none; background-color: #cdc7c2; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } ++button.keyboard-activating.sidebar-button, notebook > header > tabs > arrow.keyboard-activating, windowcontrols button.keyboard-activating, .toolbar button.keyboard-activating, button.sidebar-button:active, notebook > header > tabs > arrow:active, windowcontrols button:active, .toolbar button:active, button.sidebar-button:checked, notebook > header > tabs > arrow:checked, windowcontrols button:checked, .toolbar button:checked, button.flat.keyboard-activating, button.flat:active, button.flat:checked { border-color: transparent; background-image: none; box-shadow: none; background-color: #cdc7c2; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + - button.sidebar-button:backdrop, notebook > header > tabs > arrow:backdrop, windowcontrols button:backdrop, button.sidebar-button:disabled, notebook > header > tabs > arrow:disabled, windowcontrols button:disabled, button.flat:backdrop, button.flat:disabled, button.flat:backdrop:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; } ++button.sidebar-button:backdrop, notebook > header > tabs > arrow:backdrop, windowcontrols button:backdrop, .toolbar button:backdrop, button.sidebar-button:disabled, notebook > header > tabs > arrow:disabled, windowcontrols button:disabled, .toolbar button:disabled, button.flat:backdrop, button.flat:disabled, button.flat:backdrop:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; } + +notebook > header > tabs > arrow.image-button, button.image-button { min-width: 24px; padding-left: 5px; padding-right: 5px; } + +notebook > header > tabs > arrow.text-button, button.text-button { padding-left: 16px; padding-right: 16px; } + +notebook > header > tabs > arrow.text-button.image-button, button.text-button.image-button { padding-left: 8px; padding-right: 8px; } + +notebook > header > tabs > arrow.text-button.image-button label, button.text-button.image-button label { padding-left: 8px; padding-right: 8px; } + +dropdown:drop(active) button.combo, combobox:drop(active) button.combo, notebook > header > tabs > arrow:drop(active), button:drop(active) { color: #2ec27e; border-color: #2ec27e; box-shadow: inset 0 0 0 1px #2ec27e; } + +row:selected button { border-color: #185fb4; } + +row:selected button.sidebar-button:not(:active):not(:checked):not(:hover):not(disabled), row:selected button.flat:not(:active):not(:checked):not(:hover):not(disabled) { color: #ffffff; border-color: transparent; } + +row:selected button.sidebar-button:not(:active):not(:checked):not(:hover):not(disabled):backdrop, row:selected button.flat:not(:active):not(:checked):not(:hover):not(disabled):backdrop { color: #fcfcfc; } + +button.osd { min-width: 26px; min-height: 32px; color: #eeeeec; border-radius: 5px; color: #eeeeec; outline-color: rgba(53, 132, 228, 0.5); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; border: none; box-shadow: none; } + +button.osd.image-button { min-width: 30px; } + +button.osd.image-button:only-child { margin: 4px; border-radius: 50%; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); } + +button.osd:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(27, 27, 27, 0.7)); background-clip: padding-box; border: none; box-shadow: none; } + +button.osd:active, button.osd:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(2, 2, 2, 0.7)); background-clip: padding-box; box-shadow: none; border: none; box-shadow: none; } + +.app-notification button, popover.background.touch-selection button, popover.background.magnifier button, .osd button { color: #eeeeec; outline-color: rgba(53, 132, 228, 0.5); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; } + +.app-notification button:hover, popover.background.touch-selection button:hover, popover.background.magnifier button:hover, .osd button:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(27, 27, 27, 0.7)); background-clip: padding-box; } + +.app-notification button:active, popover.background.touch-selection button:active, popover.background.magnifier button:active, .app-notification button:checked, popover.background.touch-selection button:checked, popover.background.magnifier button:checked, .osd button:active:backdrop, .osd button:active, .osd button:checked:backdrop, .osd button:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(2, 2, 2, 0.7)); background-clip: padding-box; box-shadow: none; } + +.app-notification button:disabled, popover.background.touch-selection button:disabled, popover.background.magnifier button:disabled, .osd button:disabled:backdrop, .osd button:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; } + +.app-notification button.flat, popover.background.touch-selection button.flat, popover.background.magnifier button.flat, .osd button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; box-shadow: none; -gtk-icon-shadow: 0 1px black; } + +.app-notification button.flat:hover, popover.background.touch-selection button.flat:hover, popover.background.magnifier button.flat:hover, .osd button.flat:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(27, 27, 27, 0.7)); background-clip: padding-box; } + +.app-notification button.flat:disabled, popover.background.touch-selection button.flat:disabled, popover.background.magnifier button.flat:disabled, .osd button.flat:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; background-image: none; border-color: transparent; box-shadow: none; } + +.app-notification button.flat:active, popover.background.touch-selection button.flat:active, popover.background.magnifier button.flat:active, .app-notification button.flat:checked, popover.background.touch-selection button.flat:checked, popover.background.magnifier button.flat:checked, .osd button.flat:active, .osd button.flat:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(2, 2, 2, 0.7)); background-clip: padding-box; box-shadow: none; } + +button.suggested-action { color: white; outline-color: rgba(255, 255, 255, 0.8); border-color: #15539e; background-image: linear-gradient(to top, #2c7fe3 2px, #3584e4); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +button.suggested-action { outline: 0 solid transparent; outline-offset: 4px; } + +button.suggested-action:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.8); outline-width: 2px; outline-offset: -2px; } + +button.suggested-action.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #3584e4; } + +button.suggested-action:hover { color: white; border-color: #185fb4; background-image: linear-gradient(to top, #185cb0, #1c6fd4 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +button.suggested-action:active, button.suggested-action:checked { color: white; border-color: #185fb4; background-image: image(#1961b9); box-shadow: none; } + +button.suggested-action.flat:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: rgba(53, 132, 228, 0.8); } + +button.suggested-action:disabled { color: #929595; border-color: #d5d0cc; background-image: image(#faf9f8); } + +button.suggested-action:disabled:active, button.suggested-action:disabled:checked { color: #acccf4; border-color: #185fb4; background-image: image(#2f80e3); box-shadow: none; } + +.osd button.suggested-action { color: #eeeeec; outline-color: rgba(255, 255, 255, 0.8); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 132, 228, 0.5)); background-clip: padding-box; } + +.osd button.suggested-action:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 132, 228, 0.7)); background-clip: padding-box; } + +.osd button.suggested-action:active:backdrop, .osd button.suggested-action:active, .osd button.suggested-action:checked:backdrop, .osd button.suggested-action:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(#3584e4); background-clip: padding-box; box-shadow: none; } + +.osd button.suggested-action:disabled:backdrop, .osd button.suggested-action:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; } + +button.destructive-action { color: white; outline-color: rgba(255, 255, 255, 0.8); border-color: #851015; background-image: linear-gradient(to top, #d71a23 2px, #e01b24); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +button.destructive-action { outline: 0 solid transparent; outline-offset: 4px; } + +button.destructive-action:focus:focus-visible { outline-color: rgba(255, 255, 255, 0.8); outline-width: 2px; outline-offset: -2px; } + +button.destructive-action.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #e01b24; } + +button.destructive-action:hover { color: white; border-color: #9c1319; background-image: linear-gradient(to top, #971218, #bc171e 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +button.destructive-action:active, button.destructive-action:checked { color: white; border-color: #9c1319; background-image: image(#a0131a); box-shadow: none; } + +button.destructive-action.flat:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: rgba(224, 27, 36, 0.8); } + +button.destructive-action:disabled { color: #929595; border-color: #d5d0cc; background-image: image(#faf9f8); } + +button.destructive-action:disabled:active, button.destructive-action:disabled:checked { color: #f1a5a8; border-color: #9c1319; background-image: image(#dc1d27); box-shadow: none; } + +.osd button.destructive-action { color: #eeeeec; outline-color: rgba(255, 255, 255, 0.8); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(224, 27, 36, 0.5)); background-clip: padding-box; } + +.osd button.destructive-action:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(224, 27, 36, 0.7)); background-clip: padding-box; } + +.osd button.destructive-action:active:backdrop, .osd button.destructive-action:active, .osd button.destructive-action:checked:backdrop, .osd button.destructive-action:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(#e01b24); background-clip: padding-box; box-shadow: none; } + +.osd button.destructive-action:disabled:backdrop, .osd button.destructive-action:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; } + +stackswitcher > button > label { padding: 0 6px; margin: 0 -6px; } + +stackswitcher > button > image { padding: 3px 6px; margin: -3px -6px; } + +button.font separator { background-color: transparent; } + +button.font > box { border-spacing: 6px; } + +button.font > box > box > label { font-weight: bold; } + +menubutton.circular button, button.circular { min-width: 32px; min-height: 32px; padding: 0; border-radius: 9999px; } + +menubutton.circular button label, button.circular label { padding: 0; } + +stacksidebar row.needs-attention > label, stackswitcher > button.needs-attention > label, stackswitcher > button.needs-attention > image { animation: needs_attention 150ms ease-in; background-image: radial-gradient(farthest-side, #3584e4 96%, rgba(53, 132, 228, 0)); background-size: 6px 6px, 6px 6px; background-repeat: no-repeat; background-position: right 3px, right 4px; } + +stacksidebar row.needs-attention > label:backdrop, stackswitcher > button.needs-attention > label:backdrop, stackswitcher > button.needs-attention > image:backdrop { background-size: 6px 6px, 0 0; } + +stacksidebar row.needs-attention > label:dir(rtl), stackswitcher > button.needs-attention > label:dir(rtl), stackswitcher > button.needs-attention > image:dir(rtl) { background-position: left 3px, left 4px; } + +.linked:not(.vertical) > filechooserbutton > combobox:dir(rtl):not(:last-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(rtl):not(:last-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(rtl):not(:last-child) > box > button.combo, .linked:not(.vertical) > filechooserbutton > combobox:dir(ltr):not(:first-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(ltr):not(:first-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(ltr):not(:first-child) > box > button.combo, dropdown.linked button:nth-child(2):dir(ltr), combobox.linked button:nth-child(2):dir(ltr), .linked:not(.vertical) > menubutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > dropdown:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > colorbutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > fontbutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > filechooserbutton:dir(rtl):not(:last-child) > button, .linked:not(.vertical) > menubutton:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > dropdown:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > colorbutton:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > fontbutton:dir(ltr):not(:first-child) > button, .linked:not(.vertical) > filechooserbutton:dir(ltr):not(:first-child) > button, spinbutton.vertical.linked:not(.vertical) > text:dir(rtl):not(:last-child), .linked:not(.vertical) > spinbutton:dir(rtl):not(:last-child):not(.vertical), .linked:not(.vertical) > entry:dir(rtl):not(:last-child), .linked:not(.vertical) > button:dir(rtl):not(:last-child), spinbutton.vertical.linked:not(.vertical) > text:dir(ltr):not(:first-child), .linked:not(.vertical) > spinbutton:dir(ltr):not(:first-child):not(.vertical), .linked:not(.vertical) > entry:dir(ltr):not(:first-child), .linked:not(.vertical) > button:dir(ltr):not(:first-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; } + +.linked:not(.vertical) > filechooserbutton > combobox:dir(rtl):not(:first-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(rtl):not(:first-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(rtl):not(:first-child) > box > button.combo, .linked:not(.vertical) > filechooserbutton > combobox:dir(ltr):not(:last-child) > box > button.combo, .linked:not(.vertical) > appchooserbutton > combobox:dir(ltr):not(:last-child) > box > button.combo, .linked:not(.vertical) > combobox:dir(ltr):not(:last-child) > box > button.combo, dropdown.linked button:nth-child(2):dir(rtl), combobox.linked button:nth-child(2):dir(rtl), .linked:not(.vertical) > menubutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > dropdown:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > colorbutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > fontbutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > filechooserbutton:dir(rtl):not(:first-child) > button, .linked:not(.vertical) > menubutton:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > dropdown:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > colorbutton:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > fontbutton:dir(ltr):not(:last-child) > button, .linked:not(.vertical) > filechooserbutton:dir(ltr):not(:last-child) > button, spinbutton.vertical.linked:not(.vertical) > text:dir(rtl):not(:first-child), .linked:not(.vertical) > spinbutton:dir(rtl):not(:first-child):not(.vertical), .linked:not(.vertical) > entry:dir(rtl):not(:first-child), .linked:not(.vertical) > button:dir(rtl):not(:first-child), spinbutton.vertical.linked:not(.vertical) > text:dir(ltr):not(:last-child), .linked:not(.vertical) > spinbutton:dir(ltr):not(:last-child):not(.vertical), .linked:not(.vertical) > entry:dir(ltr):not(:last-child), .linked:not(.vertical) > button:dir(ltr):not(:last-child) { border-right-style: none; border-top-right-radius: 0; border-bottom-right-radius: 0; } + +.linked.vertical > filechooserbutton > combobox:not(:first-child) > box > button.combo, .linked.vertical > appchooserbutton > combobox:not(:first-child) > box > button.combo, .linked.vertical > combobox:not(:first-child) > box > button.combo, .linked.vertical > menubutton:not(:first-child) > button, .linked.vertical > dropdown:not(:first-child) > button, .linked.vertical > colorbutton:not(:first-child) > button, .linked.vertical > fontbutton:not(:first-child) > button, .linked.vertical > filechooserbutton:not(:first-child) > button, spinbutton.vertical.linked > text:not(:first-child), .linked.vertical > spinbutton:not(:first-child):not(.vertical), .linked.vertical > entry:not(:first-child), .linked.vertical > button:not(:first-child) { border-top-left-radius: 0; border-top-right-radius: 0; } + +.linked.vertical > filechooserbutton > combobox:not(:last-child) > box > button.combo, .linked.vertical > appchooserbutton > combobox:not(:last-child) > box > button.combo, .linked.vertical > combobox:not(:last-child) > box > button.combo, .linked.vertical > menubutton:not(:last-child) > button, .linked.vertical > dropdown:not(:last-child) > button, .linked.vertical > colorbutton:not(:last-child) > button, .linked.vertical > fontbutton:not(:last-child) > button, .linked.vertical > filechooserbutton:not(:last-child) > button, spinbutton.vertical.linked > text:not(:last-child), .linked.vertical > spinbutton:not(:last-child):not(.vertical), .linked.vertical > entry:not(:last-child), .linked.vertical > button:not(:last-child) { border-bottom-style: none; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } + - .scale-popup button:hover, button.link, button.link:hover, button.link:active, button.link:checked, popover.menu box.circular-buttons button.circular.image-button.model, list > row button.image-button:not(.flat), .toolbar button, modelbutton.flat { background-color: transparent; background-image: none; border-color: transparent; box-shadow: inset 0 1px rgba(255, 255, 255, 0), 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; } ++.scale-popup button:hover, button.link, button.link:hover, button.link:active, button.link:checked, popover.menu box.circular-buttons button.circular.image-button.model, list > row button.image-button:not(.flat), modelbutton.flat { background-color: transparent; background-image: none; border-color: transparent; box-shadow: inset 0 1px rgba(255, 255, 255, 0), 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; } + +/* menu buttons */ +modelbutton.flat { min-height: 26px; padding-left: 5px; padding-right: 5px; border-radius: 5px; } + +modelbutton.flat:hover { background-color: #e8e6e3; } + +modelbutton.flat:disabled { color: #929595; } + +modelbutton.flat arrow { background: none; min-width: 16px; min-height: 16px; opacity: 0.3; } + +modelbutton.flat arrow:hover { background: none; } + +modelbutton.flat arrow.left { -gtk-icon-source: -gtk-icontheme("go-previous-symbolic"); } + +modelbutton.flat arrow.right { -gtk-icon-source: -gtk-icontheme("go-next-symbolic"); } + +/* oldstyle toolbar buttons */ +.toolbar button { margin: 1px; } + - .toolbar button:hover { color: #2e3436; border-color: #cdc7c2; background-image: linear-gradient(to top, #d6d1cd, #e8e6e3 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } - - .toolbar button:active { color: #2e3436; border-color: #cdc7c2; background-image: image(#dad6d2); box-shadow: none; } - - .toolbar button:disabled { color: #929595; border-color: #d5d0cc; background-image: image(#faf9f8); } - - .toolbar button:backdrop { color: #929595; border-color: #d5d0cc; background-image: image(#f6f5f4); box-shadow: none; } - - .toolbar button:backdrop:disabled { color: #d4cfca; border-color: #d5d0cc; background-image: image(#faf9f8); box-shadow: none; } - +button.color { padding: 4px; } + +button.color > colorswatch:only-child { box-shadow: 0 1px rgba(0, 0, 0, 0.1); } + +button.color > colorswatch:only-child, button.color > colorswatch:only-child > overlay { border-radius: 0; } + +.osd button.color > colorswatch:only-child { box-shadow: none; } + +.osd button.color:disabled colorswatch:only-child, .osd button.color:active colorswatch:only-child, .osd button.color:checked colorswatch:only-child, button.color:disabled colorswatch:only-child, button.color:active colorswatch:only-child, button.color:checked colorswatch:only-child { box-shadow: none; } + +/* list buttons */ +/* tone down as per new designs, see issue #1473 */ +popover.menu box.circular-buttons button.circular.image-button.model, list > row button.image-button:not(.flat) { border: 1px solid rgba(205, 199, 194, 0.5); } + +popover.menu box.circular-buttons button.circular.image-button.model:hover, list > row button.image-button:not(.flat):hover { color: #2e3436; border-color: #cdc7c2; background-image: linear-gradient(to top, #d6d1cd, #e8e6e3 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +popover.menu box.circular-buttons button.circular.image-button.model:active, popover.menu box.circular-buttons button.circular.image-button.model:checked, list > row button.image-button:not(.flat):active, list > row button.image-button:not(.flat):checked { color: #2e3436; border-color: #cdc7c2; background-image: image(#dad6d2); box-shadow: none; } + +popover.menu box.circular-buttons button.suggested-action.circular.image-button.model, list > row button.image-button.suggested-action:not(.flat) { color: white; outline-color: rgba(255, 255, 255, 0.8); border-color: #15539e; background-image: linear-gradient(to top, #2c7fe3 2px, #3584e4); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +popover.menu box.circular-buttons button.suggested-action.circular.image-button.model, list > row button.image-button.suggested-action:not(.flat) { outline: 0 solid transparent; outline-offset: 4px; } + +popover.menu box.circular-buttons button.suggested-action.circular.image-button.model:focus:focus-visible, list > row button.image-button.suggested-action:not(.flat):focus:focus-visible { outline-color: rgba(255, 255, 255, 0.8); outline-width: 2px; outline-offset: -2px; } + +popover.menu box.circular-buttons button.destructive-action.circular.image-button.model, list > row button.image-button.destructive-action:not(.flat) { color: white; outline-color: rgba(255, 255, 255, 0.8); border-color: #851015; background-image: linear-gradient(to top, #d71a23 2px, #e01b24); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +popover.menu box.circular-buttons button.destructive-action.circular.image-button.model, list > row button.image-button.destructive-action:not(.flat) { outline: 0 solid transparent; outline-offset: 4px; } + +popover.menu box.circular-buttons button.destructive-action.circular.image-button.model:focus:focus-visible, list > row button.image-button.destructive-action:not(.flat):focus:focus-visible { outline-color: rgba(255, 255, 255, 0.8); outline-width: 2px; outline-offset: -2px; } + +/********* Links * */ +button.link, link { color: #1b6acb; text-decoration: underline; } + +button.link:visited, link:visited { color: #15539e; } + +*:selected button.link:visited, *:selected link:visited { color: #a1bad8; } + +button.link:hover, link:hover { color: #3584e4; } + +*:selected button.link:hover, *:selected link:hover { color: #ebf3fc; } + +button.link:active, link:active { color: #1b6acb; } + +*:selected button.link:active, *:selected link:active { color: #d1e1f5; } + +button.link:disabled, link:disabled { color: rgba(115, 115, 115, 0.8); } + +button.link:selected, *:selected button.link, link:selected, *:selected link { color: #d1e1f5; } + +link { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +link { outline: 0 solid transparent; outline-offset: 4px; } + +link:focus:focus-visible { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: -2px; } + +button.link, button.link:hover, button.link:active, button.link:checked { text-shadow: none; } + +button.link > label { text-decoration: underline; } + +/***************** GtkSpinButton * */ +spinbutton { font-feature-settings: "tnum"; } + +spinbutton:not(.vertical) { padding: 0; border-spacing: 0; /* :not here just to bump specificity above that of the list button styling */ } + +.osd spinbutton:not(.vertical) > text, spinbutton:not(.vertical) > text { min-width: 28px; margin: 0; background: none; background-color: transparent; border: none; border-radius: 0; box-shadow: none; padding: 6px; } + +.osd spinbutton:not(.vertical) > text:backdrop:disabled, spinbutton:not(.vertical) > text:backdrop:disabled { background-color: transparent; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat), spinbutton:not(.vertical) > button.image-button.down:not(.flat) { min-height: 16px; margin: 0; padding-bottom: 0; padding-top: 0; color: #43484a; background-image: none; border-style: none none none solid; border-color: rgba(205, 199, 194, 0.3); border-radius: 0; box-shadow: none; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl), spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl) { border-style: none solid none none; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):hover, spinbutton:not(.vertical) > button.image-button.down:not(.flat):hover { color: #2e3436; background-color: #ebe8e6; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):disabled, spinbutton:not(.vertical) > button.image-button.down:not(.flat):disabled { color: rgba(146, 149, 149, 0.3); background-color: transparent; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):active, spinbutton:not(.vertical) > button.image-button.down:not(.flat):active { background-color: rgba(0, 0, 0, 0.1); box-shadow: inset 0 2px 3px -1px rgba(0, 0, 0, 0.2); } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(ltr):last-child, spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(ltr):last-child { border-radius: 0 5px 5px 0; } + +spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl):first-child, spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl):first-child { border-radius: 5px 0 0 5px; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat), .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat) { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #eeeeec; border-style: none none none solid; border-color: rgba(0, 0, 0, 0.4); border-radius: 0; box-shadow: none; -gtk-icon-shadow: 0 1px black; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl), .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl) { border-style: none solid none none; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):hover, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):hover { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #eeeeec; border-color: rgba(0, 0, 0, 0.5); background-color: rgba(27, 27, 27, 0.7); -gtk-icon-shadow: 0 1px black; box-shadow: none; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):disabled, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; color: #919190; border-color: rgba(0, 0, 0, 0.5); -gtk-icon-shadow: none; box-shadow: none; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(ltr):last-child, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(ltr):last-child { border-radius: 0 5px 5px 0; } + +.osd spinbutton:not(.vertical) > button.image-button.up:not(.flat):dir(rtl):first-child, .osd spinbutton:not(.vertical) > button.image-button.down:not(.flat):dir(rtl):first-child { border-radius: 5px 0 0 5px; } + +spinbutton.vertical:disabled { color: #929595; } + +spinbutton.vertical:drop(active) { border-color: transparent; box-shadow: none; } + +spinbutton.vertical > text { min-height: 32px; min-width: 32px; padding: 0; border-radius: 0; } + +spinbutton.vertical > text > block-cursor { color: #ffffff; background-color: black; } + +spinbutton.vertical > button { min-height: 32px; min-width: 32px; padding: 0; } + +spinbutton.vertical > button.up { border-bottom-style: none; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } + +spinbutton.vertical > button.down { border-top-style: none; border-top-left-radius: 0; border-top-right-radius: 0; } + +.osd spinbutton.vertical > button:first-child { color: #eeeeec; outline-color: rgba(53, 132, 228, 0.5); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; } + +.osd spinbutton.vertical > button:first-child:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(27, 27, 27, 0.7)); background-clip: padding-box; } + +.osd spinbutton.vertical > button:first-child:active { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(2, 2, 2, 0.7)); background-clip: padding-box; box-shadow: none; } + +.osd spinbutton.vertical > button:first-child:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; } + +treeview spinbutton:not(.vertical) { min-height: 0; border-style: none; border-radius: 0; } + +treeview spinbutton:not(.vertical) > text { min-height: 0; padding: 1px 2px; } + +/************** ComboBoxes * */ +dropdown > popover.menu.background > contents { padding: 0; } + +dropdown > button > box { border-spacing: 6px; } + +dropdown > button > box > stack > row.activatable:hover { background: none; box-shadow: none; } + +dropdown arrow, combobox arrow { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); min-height: 16px; min-width: 16px; } + +dropdown > popover.menu > contents modelbutton, combobox > popover.menu > contents modelbutton { padding-left: 9px; padding-right: 9px; } + +dropdown:drop(active), combobox:drop(active) { box-shadow: none; } + +dropdown popover, combobox popover { margin-top: 6px; padding: 0; } + +dropdown popover listview, combobox popover listview { margin: 8px 0; } + +dropdown popover listview > row.activatable, combobox popover listview > row.activatable { padding: 8px; } + +dropdown popover listview > row.activatable:selected, dropdown popover listview > row.activatable:selected:hover, combobox popover listview > row.activatable:selected, combobox popover listview > row.activatable:selected:hover { outline-color: rgba(255, 255, 255, 0.8); color: black; background-color: #e8e6e3; box-shadow: none; } + +dropdown popover .dropdown-searchbar, combobox popover .dropdown-searchbar { padding: 6px; border-bottom: 1px solid #cdc7c2; } + +/************ Toolbars * */ +searchbar > revealer > box, .toolbar, toolbar { padding: 4px; border-spacing: 4px; background-color: #f6f5f4; } + +.osd .toolbar, .osd toolbar { background-color: transparent; } + +.toolbar.osd, toolbar.osd { padding: 13px; border: none; border-radius: 5px; background-color: rgba(53, 53, 53, 0.7); } + +.toolbar.osd.left, .toolbar.osd.right, .toolbar.osd.top, .toolbar.osd.bottom, toolbar.osd.left, toolbar.osd.right, toolbar.osd.top, toolbar.osd.bottom { border-radius: 0; } + +.toolbar.horizontal > separator, toolbar.horizontal > separator { margin: 4px 0; } + +.toolbar.vertical > separator, toolbar.vertical > separator { margin: 0 4px; } + +searchbar > revealer > box { padding: 6px; border-spacing: 6px; border-width: 0 0 1px; } + +searchbar > revealer > box { border-style: solid; border-color: #cdc7c2; background-color: #eae7e5; } + +searchbar > revealer > box:backdrop { border-color: #d5d0cc; background-color: #eae8e6; box-shadow: none; transition: 200ms ease-out; } + +/************** GtkInfoBar * */ +infobar > revealer > box { padding: 8px; border-spacing: 12px; } + +infobar.action:hover > revealer > box { background-color: #f4ebe1; } + +infobar.info > revealer > box, infobar.question > revealer > box, infobar.warning > revealer > box, infobar.error > revealer > box { border-bottom: 1px solid #d8d4d0; background-color: #f1e6d9; } + +infobar .close, searchbar .close { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; min-width: 16px; min-height: 16px; padding: 4px; border-radius: 50%; } + +infobar .close:hover, searchbar .close:hover { color: #2e3436; border-color: #cdc7c2; background-image: linear-gradient(to top, #d6d1cd, #e8e6e3 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +/***************** Title buttons * */ +windowcontrols { border-spacing: 6px; } + +windowcontrols.start:not(.empty):dir(ltr), windowcontrols.end:not(.empty):dir(rtl) { margin-right: 7px; } + +windowcontrols.start:not(.empty):dir(rtl), windowcontrols.end:not(.empty):dir(ltr) { margin-left: 7px; } + +windowcontrols button { border-radius: 9999px; padding: 6px; margin: 0 2px; min-width: 0; min-height: 0; } + +windowcontrols button:hover { border-color: transparent; background-image: none; box-shadow: none; background-color: #d1ccc7; } + +windowcontrols button:active, windowcontrols button:checked { border-color: transparent; background-image: none; box-shadow: none; background-color: #bab3ab; } + +/*************** Header bars * */ +.titlebar:not(headerbar), headerbar { padding: 0 6px; min-height: 46px; border-width: 0 0 1px; border-style: solid; border-color: #bfb8b1; border-radius: 0; background: #dfdcd8 linear-gradient(to top, #dad6d2, #e1dedb); /* Darken switchbuttons for headerbars. issue #1588 */ } + +.titlebar:backdrop:not(headerbar), headerbar:backdrop { border-color: #d5d0cc; background-color: #f6f5f4; background-image: none; transition: 200ms ease-out; } + +.titlebar:not(headerbar) .title, headerbar .title { padding-left: 12px; padding-right: 12px; font-weight: bold; } + +.titlebar:not(headerbar) .subtitle, headerbar .subtitle { font-size: smaller; padding-left: 12px; padding-right: 12px; } + +.titlebar:not(headerbar) stackswitcher > button:checked, .titlebar:not(headerbar) button.toggle:checked, headerbar stackswitcher > button:checked, headerbar button.toggle:checked { background: image(#cfcac4); border-color: #c6bfb9; border-top-color: #bab3ab; } + +.titlebar:not(headerbar) stackswitcher > button:checked:backdrop, .titlebar:not(headerbar) button.toggle:checked:backdrop, headerbar stackswitcher > button:checked:backdrop, headerbar button.toggle:checked:backdrop { color: #929595; border-color: #d5d0cc; background-image: image(#e9e9e3); box-shadow: none; } + +.tiled .titlebar:not(headerbar), .tiled-top .titlebar:not(headerbar), .tiled-left .titlebar:not(headerbar), .tiled-right .titlebar:not(headerbar), .tiled-bottom .titlebar:not(headerbar), .maximized .titlebar:not(headerbar), .fullscreen .titlebar:not(headerbar), .tiled headerbar, .tiled-top headerbar, .tiled-left headerbar, .tiled-right headerbar, .tiled-bottom headerbar, .maximized headerbar, .fullscreen headerbar { border-radius: 0; } + +.default-decoration.titlebar:not(headerbar), headerbar.default-decoration { min-height: 28px; padding: 4px; } + +.default-decoration.titlebar:not(headerbar) windowcontrols button, .default-decoration.titlebar:not(headerbar) windowcontrols menubutton, headerbar.default-decoration windowcontrols button, headerbar.default-decoration windowcontrols menubutton { min-height: 26px; min-width: 26px; margin: 0; padding: 0; } + +.default-decoration.titlebar:not(headerbar) windowcontrols menubutton button, headerbar.default-decoration windowcontrols menubutton button { min-height: 20px; min-width: 20px; margin: 0; padding: 4px; } + +.solid-csd .titlebar:dir(rtl):not(headerbar), .solid-csd .titlebar:dir(ltr):not(headerbar), .solid-csd headerbar:backdrop:dir(rtl), .solid-csd headerbar:backdrop:dir(ltr), .solid-csd headerbar:dir(rtl), .solid-csd headerbar:dir(ltr) { margin-left: -1px; margin-right: -1px; margin-top: -1px; border-radius: 0; box-shadow: none; } + +headerbar > windowhandle > box, headerbar > windowhandle > box > box.start, headerbar > windowhandle > box > box.end { border-spacing: 6px; } + +headerbar entry, headerbar spinbutton, headerbar separator:not(.sidebar), headerbar button, headerbar menubutton { margin-top: 6px; margin-bottom: 6px; } + +headerbar menubutton > button { margin-top: 0px; margin-bottom: 0px; } + +headerbar switch { margin-top: 10px; margin-bottom: 10px; } + +window.csd > .titlebar:not(headerbar) { padding: 0; background-color: transparent; background-image: none; border-style: none; border-color: transparent; } + +.titlebar:not(headerbar) separator { background-color: #cdc7c2; } + +window.devel headerbar.titlebar { background: #f6f5f4 cross-fade(10% -gtk-icontheme("system-run-symbolic"), image(transparent)) 90% 0/256px 256px no-repeat, linear-gradient(to right, transparent 65%, rgba(53, 132, 228, 0.2)), linear-gradient(to top, #d8d4d0, #dfdcd8 3px, #edebe9); } + +window.devel headerbar.titlebar:backdrop { background: #f6f5f4 cross-fade(10% -gtk-icontheme("system-run-symbolic"), image(transparent)) 90% 0/256px 256px no-repeat, image(#f6f5f4); /* background-color would flash */ } + +/************ Pathbars * */ +pathbar > button.text-button, pathbar > button.image-button, pathbar > button { padding-left: 4px; padding-right: 4px; } + +pathbar > button.text-button.image-button label { padding-left: 0; padding-right: 0; } + +pathbar > button.text-button.image-button label:last-child, pathbar > button label:last-child { padding-right: 8px; } + +pathbar > button.text-button.image-button label:first-child, pathbar > button label:first-child { padding-left: 8px; } + +pathbar > button image { padding-left: 4px; padding-right: 4px; } + +pathbar > button.slider-button { padding-left: 0; padding-right: 0; } + +/************** Tree Views * */ +columnview.view, treeview.view { border-left-color: #d7d2ce; border-top-color: #d7d2ce; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +columnview.view, treeview.view { outline: 0 solid transparent; outline-offset: 4px; } + +columnview.view:focus:focus-visible, treeview.view:focus:focus-visible { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: -2px; } + +columnview.view:selected:focus, columnview.view:selected, treeview.view:selected:focus, treeview.view:selected { border-radius: 0; outline-color: rgba(255, 255, 255, 0.8); } + +columnview.view:disabled, treeview.view:disabled { color: #929595; } + +columnview.view:disabled:selected, treeview.view:disabled:selected { color: #86b5ef; } + +columnview.view:disabled:selected:backdrop, treeview.view:disabled:selected:backdrop { color: #71a8eb; } + +columnview.view.separator, treeview.view.separator { min-height: 2px; color: #d7d2ce; } + +columnview.view:backdrop, treeview.view:backdrop { border-left-color: #ddd9d6; border-top: #ddd9d6; } + +columnview.view:drop(active), treeview.view:drop(active) { box-shadow: none; } + +columnview.view > dndtarget:drop(active), treeview.view > dndtarget:drop(active) { border-style: solid none; border-width: 1px; border-color: #185fb4; } + +columnview.view > dndtarget.after:drop(active), treeview.view > dndtarget.after:drop(active) { border-top-style: none; } + +columnview.view > dndtarget.before:drop(active), treeview.view > dndtarget.before:drop(active) { border-bottom-style: none; } + +columnview.view.expander, treeview.view.expander { min-width: 16px; min-height: 16px; -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); color: #4d4d4d; } + +columnview.view.expander:dir(rtl), treeview.view.expander:dir(rtl) { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl"); } + +columnview.view.expander:hover, treeview.view.expander:hover { color: black; } + +columnview.view.expander:selected, treeview.view.expander:selected { color: #c2daf7; } + +columnview.view.expander:selected:hover, treeview.view.expander:selected:hover { color: #ffffff; } + +columnview.view.expander:checked, treeview.view.expander:checked { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +columnview.view.progressbar, treeview.view.progressbar { color: #ffffff; background-color: #3584e4; background-image: image(#3584e4); box-shadow: none; } + +columnview.view.progressbar:selected:focus, columnview.view.progressbar:selected, treeview.view.progressbar:selected:focus, treeview.view.progressbar:selected { color: #3584e4; background-image: image(#ffffff); } + +columnview.view.progressbar:selected:focus:backdrop, columnview.view.progressbar:selected:backdrop, treeview.view.progressbar:selected:focus:backdrop, treeview.view.progressbar:selected:backdrop { color: #3584e4; background-color: #fcfcfc; } + +columnview.view.trough, treeview.view.trough { background-color: rgba(46, 52, 54, 0.1); } + +columnview.view.trough:selected:focus, columnview.view.trough:selected, treeview.view.trough:selected:focus, treeview.view.trough:selected { background-color: rgba(255, 255, 255, 0.3); } + +columnview.view > header > button, treeview.view > header > button { color: #979a9b; background-color: #ffffff; font-weight: bold; text-shadow: none; box-shadow: none; } + +columnview.view > header > button:hover, treeview.view > header > button:hover { color: #636769; box-shadow: none; transition: none; } + +columnview.view > header > button:active, treeview.view > header > button:active { color: #2e3436; transition: none; } + +columnview.view > header > button sort-indicator, treeview.view > header > button sort-indicator { min-height: 16px; min-width: 16px; } + +columnview.view > header > button sort-indicator.ascending, treeview.view > header > button sort-indicator.ascending { -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); } + +columnview.view > header > button sort-indicator.descending, treeview.view > header > button sort-indicator.descending { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +columnview.view button.dnd:active, columnview.view button.dnd:selected, columnview.view button.dnd:hover, columnview.view button.dnd, columnview.view header.button.dnd:active, columnview.view header.button.dnd:selected, columnview.view header.button.dnd:hover, columnview.view header.button.dnd, treeview.view button.dnd:active, treeview.view button.dnd:selected, treeview.view button.dnd:hover, treeview.view button.dnd, treeview.view header.button.dnd:active, treeview.view header.button.dnd:selected, treeview.view header.button.dnd:hover, treeview.view header.button.dnd { padding: 0 6px; color: #ffffff; background-image: none; background-color: #3584e4; border-style: none; border-radius: 0; box-shadow: inset 0 0 0 1px #ffffff; text-shadow: none; transition: none; } + +columnview.view acceleditor > label, treeview.view acceleditor > label { background-color: #3584e4; } + +columnview.view > header > button, treeview.view > header > button, columnview.view > header > button:hover, treeview.view > header > button:hover, columnview.view > header > button:active, treeview.view > header > button:active { padding: 0 6px; background-image: none; border-style: none none solid solid; border-color: #d7d2ce; border-radius: 0; text-shadow: none; } + +columnview.view > header > button:disabled, treeview.view > header > button:disabled { border-color: #f6f5f4; background-image: none; } + +columnview.view > header > button:last-child, treeview.view > header > button:last-child { border-right-style: none; } + +/*************** Popovers * */ +popover.background { background-color: transparent; font: initial; } + +popover.background > arrow, popover.background > contents { background-color: #ffffff; background-clip: padding-box; border: 1px solid rgba(0, 0, 0, 0.23); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); } + +popover.background:backdrop { background-color: transparent; } + +popover.background > contents { padding: 8px; border-radius: 9px; } + +popover.background > contents > list, popover.background > contents > .view, popover.background > contents > iconview, popover.background > contents > toolbar { border-style: none; background-color: transparent; } + +popover.background > contents separator { background-color: #d9d5d1; margin: 3px; } + +popover.background > contents list separator { margin: 0; } + +.osd popover.background, popover.background.touch-selection, popover.background.magnifier { background-color: transparent; } + +.osd popover.background > arrow, .osd popover.background > contents, popover.background.touch-selection > arrow, popover.background.touch-selection > contents, popover.background.magnifier > arrow, popover.background.magnifier > contents { border: 1px solid rgba(255, 255, 255, 0.1); box-shadow: none; } + +magnifier { background-color: #ffffff; } + +/********************** Popover Base Menus * */ +popover.menu { padding: 0; } + +popover.menu box.inline-buttons { padding: 0 12px; } + +popover.menu box.inline-buttons button.image-button.model { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; min-height: 30px; min-width: 30px; padding: 0; border: none; outline: none; transition: none; } + +popover.menu box.inline-buttons button.image-button.model:selected { background: image(#e8e6e3); } + +popover.menu box.circular-buttons { padding: 12px 12px 6px; } + +popover.menu box.circular-buttons button.circular.image-button.model { padding: 11px; } + +popover.menu box.circular-buttons button.circular.image-button.model:focus { background-color: #e8e6e3; border-color: #e8e6e3; } + +popover.menu > arrow, popover.menu.background > contents { background-color: #ffffff; padding: 5px; } + +popover.menu.background separator { margin: 6px 0; } + +popover.menu accelerator { color: alpha(currentColor,0.55); } + +popover.menu accelerator:dir(ltr) { margin-left: 12px; } + +popover.menu accelerator:dir(rtl) { margin-right: 12px; } + +popover.menu check, popover.menu radio { transform: scale(0.8); border-width: 1.2px; border-color: transparent; box-shadow: none; background-image: image(transparent); color: black; } + +popover.menu check:hover, popover.menu radio:hover { transform: scale(0.8); border-width: 1.2px; color: black; box-shadow: none; background-image: image(transparent); } + +popover.menu check:active, popover.menu radio:active { transform: scale(0.8); border-width: 1.2px; color: black; box-shadow: none; background-image: image(transparent); } + +popover.menu radio { border-color: #cdc7c2; } + +popover.menu radio:active { border-color: rgba(205, 199, 194, 0.5); } + +popover.menu arrow.left, popover.menu radio.left, popover.menu check.left { margin-left: -2px; margin-right: 6px; } + +popover.menu arrow.right, popover.menu radio.right, popover.menu check.right { margin-left: 6px; margin-right: -2px; } + +popover.menu modelbutton { min-height: 30px; min-width: 40px; padding: 0 12px; border-radius: 5px; } + +popover.menu modelbutton:selected { color: black; background-color: #e8e6e3; } + +popover.menu modelbutton:selected:active { background-color: #d6d1cd; } + +popover.menu label.title { font-weight: bold; padding: 4px 32px; } + +menubar { padding: 0px; box-shadow: inset 0 -1px rgba(0, 0, 0, 0.1); } + +menubar > item { min-height: 16px; padding: 4px 8px; } + +menubar > item:selected { box-shadow: inset 0 -3px #3584e4; color: #1b6acb; } + +menubar > item:disabled { color: #929595; box-shadow: none; } + +menubar > item popover.menu.background > contents { padding: 5px; } + +menubar > item popover.menu popover.menu { padding: 0 0 4px 0; } + +menubar > item popover.menu.background popover.menu.background > contents { margin: 0; border-radius: 9px; } + +/************* Notebooks * */ +notebook { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +notebook > header > tabs > tab:checked { outline: 0 solid transparent; outline-offset: 4px; } + +notebook:focus:focus-visible > header > tabs > tab:checked { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: -2px; } + +notebook > header { padding: 1px; border-color: #cdc7c2; border-width: 1px; background-color: #e1dedb; } + +notebook > header > tabs { margin: -1px; } + +notebook > header.top { border-bottom-style: solid; } + +notebook > header.top > tabs { margin-bottom: -2px; } + +notebook > header.top > tabs > tab:hover { box-shadow: inset 0 -4px #cdc7c2; } + +notebook > header.top > tabs > tab:checked { box-shadow: inset 0 -4px #3584e4; } + +notebook > header.bottom { border-top-style: solid; } + +notebook > header.bottom > tabs { margin-top: -2px; } + +notebook > header.bottom > tabs > tab:hover { box-shadow: inset 0 4px #cdc7c2; } + +notebook > header.bottom > tabs > tab:checked { box-shadow: inset 0 4px #3584e4; } + +notebook > header.left { border-right-style: solid; } + +notebook > header.left > tabs { margin-right: -2px; } + +notebook > header.left > tabs > tab:hover { box-shadow: inset -4px 0 #cdc7c2; } + +notebook > header.left > tabs > tab:checked { box-shadow: inset -4px 0 #3584e4; } + +notebook > header.right { border-left-style: solid; } + +notebook > header.right > tabs { margin-left: -2px; } + +notebook > header.right > tabs > tab:hover { box-shadow: inset 4px 0 #cdc7c2; } + +notebook > header.right > tabs > tab:checked { box-shadow: inset 4px 0 #3584e4; } + +notebook > header.top > tabs > arrow { border-top-style: none; } + +notebook > header.bottom > tabs > arrow { border-bottom-style: none; } + +notebook > header.top > tabs > arrow, notebook > header.bottom > tabs > arrow { margin-left: -5px; margin-right: -5px; padding-left: 4px; padding-right: 4px; } + +notebook > header.top > tabs > arrow.down, notebook > header.bottom > tabs > arrow.down { -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); } + +notebook > header.top > tabs > arrow.up, notebook > header.bottom > tabs > arrow.up { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } + +notebook > header.left > tabs > arrow { border-left-style: none; } + +notebook > header.right > tabs > arrow { border-right-style: none; } + +notebook > header.left > tabs > arrow, notebook > header.right > tabs > arrow { margin-top: -5px; margin-bottom: -5px; padding-top: 4px; padding-bottom: 4px; } + +notebook > header.left > tabs > arrow.down, notebook > header.right > tabs > arrow.down { -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); } + +notebook > header.left > tabs > arrow.up, notebook > header.right > tabs > arrow.up { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +notebook > header > tabs > arrow { min-height: 16px; min-width: 16px; border-radius: 0; } + +notebook > header > tabs > arrow:hover:not(:active):not(:backdrop) { background-clip: padding-box; background-image: none; background-color: rgba(255, 255, 255, 0.3); border-color: transparent; box-shadow: none; } + +notebook > header > tabs > arrow:disabled { border-color: transparent; background-color: transparent; background-image: none; box-shadow: none; } + +notebook > header > tabs > tab { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); min-height: 30px; min-width: 30px; padding: 3px 12px; color: #2e3436; font-weight: normal; border-width: 1px; border-color: transparent; } + +notebook > header > tabs > tab:hover { color: #2e3436; background-color: #d8d4d0; } + +notebook > header > tabs > tab.reorderable-page:hover { border-color: rgba(205, 199, 194, 0.3); background-color: rgba(246, 245, 244, 0.2); } + +notebook > header > tabs > tab:not(:checked) { outline-color: transparent; } + +notebook > header > tabs > tab:checked { color: #2e3436; } + +notebook > header > tabs > tab.reorderable-page:checked { border-color: rgba(205, 199, 194, 0.5); background-color: rgba(246, 245, 244, 0.5); } + +notebook > header > tabs > tab.reorderable-page:checked:hover { background-color: rgba(246, 245, 244, 0.7); } + +notebook > header > tabs > tab button.flat { color: alpha(currentColor,0.3); padding: 0; margin-top: 4px; margin-bottom: 4px; min-width: 20px; min-height: 20px; } + +notebook > header > tabs > tab button.flat:hover { color: currentColor; } + +notebook > header > tabs > tab button.flat:last-child { margin-left: 4px; margin-right: -4px; } + +notebook > header > tabs > tab button.flat:first-child { margin-left: -4px; margin-right: 4px; } + +notebook > header.top > tabs, notebook > header.bottom > tabs { padding-left: 4px; padding-right: 4px; } + +notebook > header.top > tabs:not(:only-child), notebook > header.bottom > tabs:not(:only-child) { margin-left: 3px; margin-right: 3px; } + +notebook > header.top > tabs:not(:only-child):first-child, notebook > header.bottom > tabs:not(:only-child):first-child { margin-left: -1px; } + +notebook > header.top > tabs:not(:only-child):last-child, notebook > header.bottom > tabs:not(:only-child):last-child { margin-right: -1px; } + +notebook > header.top > tabs > tab, notebook > header.bottom > tabs > tab { margin-left: 4px; margin-right: 4px; } + +notebook > header.top > tabs > tab.reorderable-page, notebook > header.bottom > tabs > tab.reorderable-page { border-style: none solid; } + +notebook > header.left > tabs, notebook > header.right > tabs { padding-top: 4px; padding-bottom: 4px; } + +notebook > header.left > tabs:not(:only-child), notebook > header.right > tabs:not(:only-child) { margin-top: 3px; margin-bottom: 3px; } + +notebook > header.left > tabs:not(:only-child):first-child, notebook > header.right > tabs:not(:only-child):first-child { margin-top: -1px; } + +notebook > header.left > tabs:not(:only-child):last-child, notebook > header.right > tabs:not(:only-child):last-child { margin-bottom: -1px; } + +notebook > header.left > tabs > tab, notebook > header.right > tabs > tab { margin-top: 4px; margin-bottom: 4px; } + +notebook > header.left > tabs > tab.reorderable-page, notebook > header.right > tabs > tab.reorderable-page { border-style: solid none; } + +notebook > header.top > tabs > tab { padding-bottom: 4px; } + +notebook > header.bottom > tabs > tab { padding-top: 4px; } + +notebook > stack:not(:only-child) { background-color: #ffffff; } + +/************** Scrollbars * */ +scrollbar { background-color: #cecece; transition: all 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +scrollbar.top { border-bottom: 1px solid #cdc7c2; } + +scrollbar.bottom { border-top: 1px solid #cdc7c2; } + +scrollbar.left { border-right: 1px solid #cdc7c2; } + +scrollbar.right { border-left: 1px solid #cdc7c2; } + +scrollbar > range > trough > slider { min-width: 8px; min-height: 8px; margin: -1px; border: 4px solid transparent; border-radius: 10px; background-clip: padding-box; background-color: #7e8182; transition: all 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +scrollbar > range > trough > slider:hover { background-color: #565b5c; } + +scrollbar > range > trough > slider:hover:active { background-color: #1b6acb; } + +scrollbar > range > trough > slider:disabled { background-color: transparent; } + +scrollbar > range.fine-tune > trough > slider { transition: none; min-width: 6px; min-height: 6px; } + +scrollbar > range.fine-tune.horizontal > trough > slider { border-width: 5px 4px; } + +scrollbar > range.fine-tune.vertical > trough > slider { border-width: 4px 5px; } + +scrollbar.overlay-indicator:not(.dragging):not(.hovering) { border-color: transparent; opacity: 0.4; background-color: transparent; } + +scrollbar.overlay-indicator:not(.dragging):not(.hovering) > range > trough > slider { margin: 0; min-width: 3px; min-height: 3px; background-color: #2e3436; border: 1px solid white; } + +scrollbar.overlay-indicator.horizontal:not(.dragging):not(.hovering) > range > trough > slider { margin: 0 2px; min-width: 40px; } + +scrollbar.overlay-indicator.vertical:not(.dragging):not(.hovering) > range > trough > slider { margin: 2px 0; min-height: 40px; } + +scrollbar.overlay-indicator.dragging, scrollbar.overlay-indicator.hovering { opacity: 0.8; } + +scrollbar.horizontal > range > trough > slider { min-width: 40px; } + +scrollbar.vertical > range > trough > slider { min-height: 40px; } + +treeview ~ scrollbar.vertical { border-top: 1px solid #cdc7c2; margin-top: -1px; } + +/********** Switch * */ +switch { font-weight: bold; font-size: smaller; border: 1px solid #cdc7c2; border-radius: 14px; color: #2e3436; background-color: #e1dedb; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; /* only show i / o for the accessible theme */ } + +switch { outline: 0 solid transparent; outline-offset: 4px; } + +switch:focus:focus-visible { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: 0; } + +headerbar switch { background-color: #cecac5; } + +switch:checked { color: #ffffff; border-color: #185fb4; background-color: #3584e4; } + +switch:disabled { color: #929595; border-color: #cdc7c2; background-color: #faf9f8; text-shadow: none; } + +switch > slider { color: #2e3436; outline-color: rgba(53, 132, 228, 0.5); border-color: #cdc7c2; background-image: linear-gradient(to top, #f6f5f4 2px, #fbfafa); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); margin: -1px; min-width: 24px; min-height: 24px; border: 1px solid; border-color: #cdc7c2; border-radius: 50%; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +switch > image { color: transparent; } + +switch:hover > slider { color: #2e3436; border-color: #cdc7c2; background-image: linear-gradient(to top, #d6d1cd, #e8e6e3 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +switch:checked > slider { border: 1px solid #185fb4; } + +switch:disabled > slider { color: #929595; border-color: #d5d0cc; background-image: image(#faf9f8); } + +row:selected switch { outline-color: rgba(255, 255, 255, 0.8); box-shadow: none; border-color: #185fb4; } + +row:selected switch > slider:checked, row:selected switch > slider { border-color: #185fb4; } + +/************************* Check and Radio items * */ +.view.content-view.check:not(list), iconview.content-view.check:not(list), .content-view .tile check:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #3584e4; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:hover:not(list), iconview.content-view.check:hover:not(list), .content-view .tile check:hover:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #3584e4; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:active:not(list), iconview.content-view.check:active:not(list), .content-view .tile check:active:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #3584e4; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:backdrop:not(list), iconview.content-view.check:backdrop:not(list), .content-view .tile check:backdrop:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: #8d8d8d; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; } + +.view.content-view.check:checked:not(list), iconview.content-view.check:checked:not(list), .content-view .tile check:checked:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: #3584e4; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +.view.content-view.check:checked:hover:not(list), iconview.content-view.check:checked:hover:not(list), .content-view .tile check:checked:hover:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: #3584e4; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +.view.content-view.check:checked:active:not(list), iconview.content-view.check:checked:active:not(list), .content-view .tile check:checked:active:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: #3584e4; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +.view.content-view.check:backdrop:checked:not(list), iconview.content-view.check:backdrop:checked:not(list), .content-view .tile check:backdrop:checked:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: rgba(238, 238, 236, 0.8); background-color: #8d8d8d; border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; } + +checkbutton { border-spacing: 4px; border-radius: 5px; transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +checkbutton { outline: 0 solid transparent; outline-offset: 4px; } + +checkbutton:focus:focus-visible { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: -2px; } + +checkbutton.text-button { padding: 4px; } + +check, radio { min-height: 14px; min-width: 14px; border: 1px solid; -gtk-icon-source: none; } + +check, radio { background-clip: padding-box; background-image: linear-gradient(to bottom, white 20%, white 90%); border-color: #bfb8b1; box-shadow: 0 1px rgba(0, 0, 0, 0.05); color: #ffffff; } + +check:hover, radio:hover { background-image: image(#f2f2f2); } + +check:active, radio:active { box-shadow: inset 0 1px rgba(0, 0, 0, 0.2); background-image: image(#d9d9d9); } + +check:disabled, radio:disabled { box-shadow: none; color: rgba(255, 255, 255, 0.7); } + +check:checked, radio:checked { background-clip: border-box; background-image: linear-gradient(to bottom, #4b92e7 20%, #3584e4 90%); border-color: #1b6acb; box-shadow: 0 1px rgba(0, 0, 0, 0.05); color: #ffffff; } + +check:checked:hover, radio:checked:hover { background-image: linear-gradient(to bottom, #5d9de9 10%, #478fe6 90%); } + +check:checked:active, radio:checked:active { box-shadow: inset 0 1px rgba(0, 0, 0, 0.2); background-image: image(#1f76e1); } + +check:checked:disabled, radio:checked:disabled { box-shadow: none; color: rgba(255, 255, 255, 0.7); } + +check:indeterminate, radio:indeterminate { background-clip: border-box; background-image: linear-gradient(to bottom, #4b92e7 20%, #3584e4 90%); border-color: #1b6acb; box-shadow: 0 1px rgba(0, 0, 0, 0.05); color: #ffffff; } + +check:indeterminate:hover, radio:indeterminate:hover { background-image: linear-gradient(to bottom, #5d9de9 10%, #478fe6 90%); } + +check:indeterminate:active, radio:indeterminate:active { box-shadow: inset 0 1px rgba(0, 0, 0, 0.2); background-image: image(#1f76e1); } + +check:indeterminate:disabled, radio:indeterminate:disabled { box-shadow: none; color: rgba(255, 255, 255, 0.7); } + +row:selected check, row:selected radio { border-color: #1b6acb; } + +.osd check, .osd radio { color: #eeeeec; outline-color: rgba(53, 132, 228, 0.5); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; } + +.osd check:hover, .osd radio:hover { color: #eeeeec; outline-color: rgba(53, 132, 228, 0.5); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; } + +.osd check:active, .osd radio:active { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(2, 2, 2, 0.7)); background-clip: padding-box; box-shadow: none; } + +.osd check:disabled, .osd radio:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; } + +check { border-radius: 3px; -gtk-icon-size: 14px; } + +check:checked { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets/check-symbolic.symbolic.png")), -gtk-recolor(url("assets/check@2-symbolic.symbolic.png"))); } + +check:indeterminate { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets/dash-symbolic.symbolic.png")), -gtk-recolor(url("assets/dash@2-symbolic.symbolic.png"))); } + +treeview.view radio:selected:focus, treeview.view radio:selected, radio { border-radius: 100%; -gtk-icon-size: 14px; } + +treeview.view radio:checked:selected, radio:checked { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets/bullet-symbolic.symbolic.png")), -gtk-recolor(url("assets/bullet@2-symbolic.symbolic.png"))); } + +treeview.view radio:indeterminate:selected, radio:indeterminate { -gtk-icon-source: -gtk-scaled(-gtk-recolor(url("assets/dash-symbolic.symbolic.png")), -gtk-recolor(url("assets/dash@2-symbolic.symbolic.png"))); } + +treeview.view check:selected:focus, treeview.view check:selected, treeview.view radio:selected:focus, treeview.view radio:selected { color: #ffffff; border-color: #185fb4; } + +/************ GtkScale * */ +progressbar > trough, scale > trough > fill, scale > trough { border: 1px solid #e1dedb; border-radius: 3px; background-color: #e1dedb; } + +headerbar progressbar > trough, headerbar scale > trough > fill, headerbar scale > trough { background-color: #cecac5; } + +progressbar > trough:disabled, scale > trough > fill:disabled, scale > trough:disabled { background-color: #faf9f8; border-color: #d5d0cc; } + +row:selected progressbar > trough, row:selected scale > trough > fill, row:selected scale > trough { outline-color: rgba(255, 255, 255, 0.8); border-color: #185fb4; } + +.osd progressbar > trough, .osd scale > trough > fill, .osd scale > trough { border-color: rgba(0, 0, 0, 0.7); background-color: rgba(0, 0, 0, 0.5); } + +.osd progressbar > trough:disabled, .osd scale > trough > fill:disabled, .osd scale > trough:disabled { background-color: rgba(71, 71, 71, 0.5); } + +progressbar > trough > progress, scale > trough > highlight { border: 1px solid #3584e4; border-radius: 3px; background-color: #3584e4; } + +progressbar > trough > progress:disabled, scale > trough > highlight:disabled { background-color: transparent; border-color: transparent; } + +row:selected progressbar > trough > progress, row:selected scale > trough > highlight { border-color: #185fb4; } + +.osd progressbar > trough > progress, .osd scale > trough > highlight { border-color: rgba(0, 0, 0, 0.7); } + +.osd progressbar > trough > progress:disabled, .osd scale > trough > highlight:disabled { border-color: transparent; } + +scale { min-height: 10px; min-width: 10px; padding: 12px; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +scale > trough { outline: 0 solid transparent; outline-offset: 16px; } + +scale:focus:focus-visible > trough { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: 10px; } + +scale > trough { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + +scale > trough > fill, scale > trough > highlight { margin: -1px; } + +scale > trough > slider { min-height: 18px; min-width: 18px; margin: -9px; } + +scale.fine-tune.horizontal { padding-top: 9px; padding-bottom: 9px; min-height: 16px; } + +scale.fine-tune.vertical { padding-left: 9px; padding-right: 9px; min-width: 16px; } + +scale.fine-tune > trough > slider { margin: -6px; } + +scale.fine-tune > trough > fill, scale.fine-tune > trough > highlight, scale.fine-tune > trough { border-radius: 5px; } + +scale > trough > fill:disabled { border-color: transparent; background-color: transparent; } + +.osd scale > trough > fill { background-color: rgba(91, 91, 90, 0.775); } + +.osd scale > trough > fill:disabled { border-color: transparent; background-color: transparent; } + +scale > trough > slider { color: #2e3436; outline-color: rgba(53, 132, 228, 0.5); border-color: #cdc7c2; background-image: linear-gradient(to top, #f6f5f4 2px, #fbfafa); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); border-width: 1px; border-style: solid; border-radius: 100%; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: background, border, box-shadow; } + +scale > trough > slider:hover { color: #2e3436; border-color: #cdc7c2; background-image: linear-gradient(to top, #d6d1cd, #e8e6e3 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +scale > trough > slider:active { border-color: #185fb4; } + +scale > trough > slider:disabled { color: #929595; border-color: #d5d0cc; background-image: image(#faf9f8); } + +row:selected scale > trough > slider:disabled, row:selected scale > trough > slider { border-color: #185fb4; } + +.osd scale > trough > slider { color: #eeeeec; outline-color: rgba(53, 132, 228, 0.5); border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; border-color: rgba(0, 0, 0, 0.7); background-color: #353535; } + +.osd scale > trough > slider:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(27, 27, 27, 0.7)); background-clip: padding-box; background-color: #353535; } + +.osd scale > trough > slider:active { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(2, 2, 2, 0.7)); background-clip: padding-box; box-shadow: none; background-color: #353535; } + +.osd scale > trough > slider:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; background-color: #353535; } + +scale > value { color: alpha(currentColor,0.55); font-feature-settings: "tnum"; } + +scale.horizontal > marks { color: alpha(currentColor,0.55); } + +scale.horizontal > marks.top { margin-bottom: 6px; } + +scale.horizontal > marks.bottom { margin-top: 6px; } + +scale.horizontal > marks indicator { background-color: currentColor; min-height: 6px; min-width: 1px; } + +scale.horizontal > value.left { margin-right: 9px; } + +scale.horizontal > value.right { margin-left: 9px; } + +scale.horizontal.fine-tune > marks.top { margin-top: 3px; } + +scale.horizontal.fine-tune > marks.bottom { margin-bottom: 3px; } + +scale.horizontal.fine-tune > marks indicator { min-height: 3px; } + +scale.vertical > marks { color: alpha(currentColor,0.55); } + +scale.vertical > marks.top { margin-right: 6px; } + +scale.vertical > marks.bottom { margin-left: 6px; } + +scale.vertical > marks indicator { background-color: currentColor; min-height: 1px; min-width: 6px; } + +scale.vertical > value.top { margin-bottom: 9px; } + +scale.vertical > value.bottom { margin-top: 9px; } + +scale.vertical.fine-tune > marks.top { margin-left: 3px; } + +scale.vertical.fine-tune > marks.bottom { margin-right: 3px; } + +scale.vertical.fine-tune > marks indicator { min-height: 3px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above.png"), url("assets/slider-horz-scale-has-marks-above@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above-hover.png"), url("assets/slider-horz-scale-has-marks-above-hover@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above-active.png"), url("assets/slider-horz-scale-has-marks-above-active@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-before:not(.marks-after) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above-insensitive.png"), url("assets/slider-horz-scale-has-marks-above-insensitive@2.png")); min-height: 26px; min-width: 22px; margin-top: -14px; background-position: top; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -7px -10px; margin-top: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-below.png"), url("assets/slider-horz-scale-has-marks-below@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-below-hover.png"), url("assets/slider-horz-scale-has-marks-below-hover@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-below-active.png"), url("assets/slider-horz-scale-has-marks-below-active@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.horizontal.marks-after:not(.marks-before) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-horz-scale-has-marks-below-insensitive.png"), url("assets/slider-horz-scale-has-marks-below-insensitive@2.png")); min-height: 26px; min-width: 22px; margin-bottom: -14px; background-position: bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.horizontal.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -7px -10px; margin-bottom: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-above.png"), url("assets/slider-vert-scale-has-marks-above@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-above-hover.png"), url("assets/slider-vert-scale-has-marks-above-hover@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-above-active.png"), url("assets/slider-vert-scale-has-marks-above-active@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-before:not(.marks-after) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-above-insensitive.png"), url("assets/slider-vert-scale-has-marks-above-insensitive@2.png")); min-height: 22px; min-width: 26px; margin-left: -14px; background-position: left bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-before.fine-tune:not(.marks-after) > trough > slider { margin: -10px -7px; margin-left: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-below.png"), url("assets/slider-vert-scale-has-marks-below@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider:hover { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-below-hover.png"), url("assets/slider-vert-scale-has-marks-below-hover@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider:active { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-below-active.png"), url("assets/slider-vert-scale-has-marks-below-active@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.vertical.marks-after:not(.marks-before) > trough > slider:disabled { margin: -10px; border-style: none; border-radius: 0; background-color: transparent; background-image: -gtk-scaled(url("assets/slider-vert-scale-has-marks-below-insensitive.png"), url("assets/slider-vert-scale-has-marks-below-insensitive@2.png")); min-height: 22px; min-width: 26px; margin-right: -14px; background-position: right bottom; background-repeat: no-repeat; box-shadow: none; } + +scale.vertical.marks-after.fine-tune:not(.marks-before) > trough > slider { margin: -10px -7px; margin-right: -11px; } + +scale.color { min-height: 0; min-width: 0; } + +scale.color > trough { background-image: image(#cdc7c2); background-repeat: no-repeat; } + +scale.color.horizontal { padding: 0 0 15px 0; } + +scale.color.horizontal > trough { padding-bottom: 4px; background-position: 0 -3px; border-top-left-radius: 0; border-top-right-radius: 0; } + +scale.color.horizontal > trough > slider:dir(ltr):hover, scale.color.horizontal > trough > slider:dir(ltr):backdrop, scale.color.horizontal > trough > slider:dir(ltr):disabled, scale.color.horizontal > trough > slider:dir(ltr):backdrop:disabled, scale.color.horizontal > trough > slider:dir(ltr), scale.color.horizontal > trough > slider:dir(rtl):hover, scale.color.horizontal > trough > slider:dir(rtl):backdrop, scale.color.horizontal > trough > slider:dir(rtl):disabled, scale.color.horizontal > trough > slider:dir(rtl):backdrop:disabled, scale.color.horizontal > trough > slider:dir(rtl) { margin-bottom: -15px; margin-top: 6px; } + +scale.color.vertical:dir(ltr) { padding: 0 0 0 15px; } + +scale.color.vertical:dir(ltr) > trough { padding-left: 4px; background-position: 3px 0; border-bottom-right-radius: 0; border-top-right-radius: 0; } + +scale.color.vertical:dir(ltr) > trough > slider:hover, scale.color.vertical:dir(ltr) > trough > slider:backdrop, scale.color.vertical:dir(ltr) > trough > slider:disabled, scale.color.vertical:dir(ltr) > trough > slider:backdrop:disabled, scale.color.vertical:dir(ltr) > trough > slider { margin-left: -15px; margin-right: 6px; } + +scale.color.vertical:dir(rtl) { padding: 0 15px 0 0; } + +scale.color.vertical:dir(rtl) > trough { padding-right: 4px; background-position: -3px 0; border-bottom-left-radius: 0; border-top-left-radius: 0; } + +scale.color.vertical:dir(rtl) > trough > slider:hover, scale.color.vertical:dir(rtl) > trough > slider:backdrop, scale.color.vertical:dir(rtl) > trough > slider:disabled, scale.color.vertical:dir(rtl) > trough > slider:backdrop:disabled, scale.color.vertical:dir(rtl) > trough > slider { margin-right: -15px; margin-left: 6px; } + +scale.color.fine-tune.horizontal:dir(ltr), scale.color.fine-tune.horizontal:dir(rtl) { padding: 0 0 12px 0; } + +scale.color.fine-tune.horizontal:dir(ltr) > trough, scale.color.fine-tune.horizontal:dir(rtl) > trough { padding-bottom: 7px; background-position: 0 -6px; } + +scale.color.fine-tune.horizontal:dir(ltr) > trough > slider, scale.color.fine-tune.horizontal:dir(rtl) > trough > slider { margin-bottom: -15px; margin-top: 6px; } + +scale.color.fine-tune.vertical:dir(ltr) { padding: 0 0 0 12px; } + +scale.color.fine-tune.vertical:dir(ltr) > trough { padding-left: 7px; background-position: 6px 0; } + +scale.color.fine-tune.vertical:dir(ltr) > trough > slider { margin-left: -15px; margin-right: 6px; } + +scale.color.fine-tune.vertical:dir(rtl) { padding: 0 12px 0 0; } + +scale.color.fine-tune.vertical:dir(rtl) > trough { padding-right: 7px; background-position: -6px 0; } + +scale.color.fine-tune.vertical:dir(rtl) > trough > slider { margin-right: -15px; margin-left: 6px; } + +/***************** Progress bars * */ +progressbar { font-size: smaller; color: rgba(46, 52, 54, 0.4); font-feature-settings: "tnum"; } + +progressbar.horizontal > trough { min-width: 150px; } + +progressbar.horizontal > trough, progressbar.horizontal > trough > progress { min-height: 2px; } + +progressbar.vertical > trough { min-height: 80px; } + +progressbar.vertical > trough, progressbar.vertical > trough > progress { min-width: 2px; } + +progressbar.horizontal > trough > progress { margin: 0 -1px; } + +progressbar.vertical > trough > progress { margin: -1px 0; } + +progressbar > trough > progress { /* share most of scales' */ /* override insensitive that is specific to progress */ border-radius: 1.5px; } + +progressbar > trough > progress:disabled { background-color: #929595; border-color: #929595; } + +progressbar > trough > progress.left { border-top-left-radius: 5px; border-bottom-left-radius: 5px; } + +progressbar > trough > progress.right { border-top-right-radius: 5px; border-bottom-right-radius: 5px; } + +progressbar > trough > progress.top { border-top-right-radius: 5px; border-top-left-radius: 5px; } + +progressbar > trough > progress.bottom { border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; } + +progressbar.osd { min-width: 3px; min-height: 3px; background-color: transparent; } + +progressbar.osd > trough { border-style: none; border-radius: 0; background-color: transparent; box-shadow: none; } + +progressbar.osd > trough > progress { border-style: none; border-radius: 0; } + +progressbar > trough.empty > progress { all: unset; } + +/************* Level Bar * */ +levelbar.horizontal trough > block { min-height: 9px; border-radius: 5px; } + +levelbar.horizontal trough > block:dir(rtl) { border-radius: 0 5px 5px 0; } + +levelbar.horizontal trough > block:dir(ltr) { border-radius: 5px 0 0 5px; } + +levelbar.horizontal trough > block.empty, levelbar.horizontal trough > block.full { border-radius: 5px; } + +levelbar.horizontal.discrete trough > block { min-height: 2px; margin: 1px; min-width: 24px; border-radius: 0; } + +levelbar.horizontal.discrete trough > block:first-child { border-radius: 2px 0 0 2px; } + +levelbar.horizontal.discrete trough > block:last-child { border-radius: 0 2px 2px 0; } + +levelbar.vertical trough > block { min-width: 9px; border-radius: 5px; } + +levelbar.vertical.discrete > trough > block { min-width: 2px; margin: 1px 0; min-height: 32px; } + +levelbar > trough { padding: 0; } + +levelbar > trough > block { border: 1px solid; } + +levelbar > trough > block.low { border-color: #f57900; background-color: #f57900; } + +levelbar > trough > block.high, levelbar > trough > block:not(.empty) { border-color: #3584e4; background-color: #3584e4; } + +levelbar > trough > block.full { border-color: #33d17a; background-color: #33d17a; } + +levelbar > trough > block.empty { background-color: #ebe8e6; border-color: #ebe8e6; } + +/**************** Print dialog * */ +window.dialog.print drawing { color: #2e3436; background: none; border: none; padding: 0; } + +window.dialog.print drawing paper { background: white; color: #2e3436; border: 1px solid #cdc7c2; } + +window.dialog.print .dialog-action-box { margin: 12px; } + +/********** Frames * */ +frame, .frame { border: 1px solid #cdc7c2; } + +frame { border-radius: 8px; } + +frame > label { margin: 4px; } + +actionbar > revealer > box { padding: 6px; border-top: 1px solid #cdc7c2; } + +actionbar > revealer > box, actionbar > revealer > box > box.start, actionbar > revealer > box > box.end { border-spacing: 6px; } + +scrolledwindow > overshoot.top { background-image: radial-gradient(farthest-side at top, #b6aea5 85%, rgba(182, 174, 165, 0)), radial-gradient(farthest-side at top, rgba(46, 52, 54, 0.07), rgba(46, 52, 54, 0)); background-size: 100% 3%, 100% 50%; background-repeat: no-repeat; background-position: top; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > overshoot.bottom { background-image: radial-gradient(farthest-side at bottom, #b6aea5 85%, rgba(182, 174, 165, 0)), radial-gradient(farthest-side at bottom, rgba(46, 52, 54, 0.07), rgba(46, 52, 54, 0)); background-size: 100% 3%, 100% 50%; background-repeat: no-repeat; background-position: bottom; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > overshoot.left { background-image: radial-gradient(farthest-side at left, #b6aea5 85%, rgba(182, 174, 165, 0)), radial-gradient(farthest-side at left, rgba(46, 52, 54, 0.07), rgba(46, 52, 54, 0)); background-size: 3% 100%, 50% 100%; background-repeat: no-repeat; background-position: left; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > overshoot.right { background-image: radial-gradient(farthest-side at right, #b6aea5 85%, rgba(182, 174, 165, 0)), radial-gradient(farthest-side at right, rgba(46, 52, 54, 0.07), rgba(46, 52, 54, 0)); background-size: 3% 100%, 50% 100%; background-repeat: no-repeat; background-position: right; background-color: transparent; border: none; box-shadow: none; } + +scrolledwindow > junction { background: #cdc7c2, linear-gradient(to bottom, transparent 1px, #cecece 1px), linear-gradient(to right, transparent 1px, #cecece 1px); } + +scrolledwindow > junction:dir(rtl) { background: #cdc7c2, linear-gradient(to bottom, transparent 1px, #cecece 1px), linear-gradient(to left, transparent 1px, #cecece 1px); } + +separator { background: #d8d4d0; min-width: 1px; min-height: 1px; } + +/********* Lists * */ +listview, list { color: black; background-color: #ffffff; border-color: #cdc7c2; } + +listview:backdrop, list:backdrop { color: #323232; background-color: #fcfcfc; border-color: #d5d0cc; } + +listview > row, list > row { padding: 2px; } + +listview > row.expander, list > row.expander { padding: 0px; } + +listview > row.expander .row-header, list > row.expander .row-header { padding: 2px; } + +listview.horizontal row.separator, listview.separators.horizontal > row:not(.separator), list.horizontal row.separator, list.separators.horizontal > row:not(.separator) { border-left: 1px solid #d7d2ce; } + +listview:not(.horizontal) row.separator, listview.separators:not(.horizontal) > row:not(.separator), list:not(.horizontal) row.separator, list.separators:not(.horizontal) > row:not(.separator) { border-bottom: 1px solid #d7d2ce; } + +row { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +row { outline: 0 solid transparent; outline-offset: 4px; } + +row:focus:focus-visible { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: -2px; } + +row.activatable.has-open-popup, row.activatable:hover { background-color: rgba(46, 52, 54, 0.05); } + +row.activatable:active { box-shadow: inset 0 2px 2px -2px rgba(0, 0, 0, 0.2); } + +row.activatable:selected:active { box-shadow: inset 0 2px 3px -1px rgba(0, 0, 0, 0.5); } + +row.activatable.has-open-popup:selected, row.activatable:selected:hover { background-color: #347cd3; } + +row:selected { outline-color: rgba(255, 255, 255, 0.8); } + +columnview > listview > row { padding: 0; } + +columnview > listview > row > cell { padding: 8px 6px; } + +columnview > listview > row > cell:not(:first-child) { border-left: 1px solid transparent; } + +columnview.column-separators > listview > row > cell { border-left-color: #d7d2ce; } + +columnview.data-table > listview > row > cell { padding-top: 2px; padding-bottom: 2px; } + +treeexpander { border-spacing: 4px; } + +/******************************************************** Data Tables * treeview like tables with individual focusable cells * https://gitlab.gnome.org/GNOME/gtk/-/issues/2929 * */ +columnview row:not(:selected) cell editablelabel:not(.editing):focus-within { outline: 2px solid rgba(53, 132, 228, 0.5); } + +columnview row:not(:selected) cell editablelabel.editing:focus-within { outline: 2px solid #3584e4; } + +columnview row:not(:selected) cell editablelabel.editing text selection { color: #ffffff; background-color: #3584e4; } + +/******************************************************* Rich Lists * Large list usually containing lots of widgets * https://gitlab.gnome.org/GNOME/gtk/-/issues/3073 * */ +.rich-list { /* rich lists usually containing other widgets than just labels/text */ } + +.rich-list > row { padding: 8px 12px; min-height: 32px; /* should be tall even when only containing a label */ } + +.rich-list > row > box { border-spacing: 12px; } + +/********************* App Notifications * */ +.app-notification { padding: 10px; border-spacing: 10px; border-radius: 0 0 5px 5px; background-color: rgba(53, 53, 53, 0.7); background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.2), transparent 2px); background-clip: padding-box; } + +.app-notification border { border: none; } + +/************* Expanders * */ +expander { min-width: 16px; min-height: 16px; -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } + +expander:dir(rtl) { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl"); } + +expander:disabled { color: #929595; } + +expander:checked { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +expander-widget { transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +expander-widget > box > title { outline: 0 solid transparent; outline-offset: 4px; } + +expander-widget:focus:focus-visible > box > title { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: -2px; } + +expander-widget > box > title { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); border-radius: 5px; } + +expander-widget > box > title:hover > expander { color: #748489; } + +.navigation-sidebar:not(decoration):not(window):drop(active):focus, .navigation-sidebar:not(decoration):not(window):drop(active), placessidebar:not(decoration):not(window):drop(active):focus, placessidebar:not(decoration):not(window):drop(active), stackswitcher:not(decoration):not(window):drop(active):focus, stackswitcher:not(decoration):not(window):drop(active), expander-widget:not(decoration):not(window):drop(active):focus, expander-widget:not(decoration):not(window):drop(active) { box-shadow: none; } + +/************ Calendar * */ +calendar { color: black; border: 1px solid #cdc7c2; } + +calendar > header { border-bottom: 1px solid #cdc7c2; } + +calendar > header > button { border: none; box-shadow: none; background: none; border-radius: 0; } + +calendar > header > button:backdrop { background: none; } + +calendar > grid > label.today { box-shadow: inset 0px -2px #cdc7c2; } + +calendar > grid > label.today:selected { box-shadow: none; } + +calendar > grid > label:focus { outline-color: rgba(53, 132, 228, 0.5); outline-offset: -2px; outline-width: 2px; outline-style: solid; } + +calendar > grid > label.day-number { padding: 4px; } + +calendar > grid > label.day-number:selected { border-radius: 3px; } + +calendar > grid > label.day-number.other-month { color: alpha(currentColor,0.3); } + +/*********** Dialogs * */ +window.dialog.message .titlebar { min-height: 20px; background-image: none; background-color: #f6f5f4; border-style: none; border-top-left-radius: 7px; border-top-right-radius: 7px; } + +window.dialog.message box.dialog-vbox.vertical { border-spacing: 10px; } + +window.dialog.message label.title { font-weight: 800; font-size: 15pt; } + +window.dialog.message.csd.background { border-bottom-left-radius: 9px; border-bottom-right-radius: 9px; } + +window.dialog.message.csd .dialog-action-area button { padding: 10px 14px; border-radius: 0; border-left-style: solid; border-right-style: none; border-bottom-style: none; } + +window.dialog.message.csd .dialog-action-area button:first-child { border-left-style: none; border-bottom-left-radius: 7px; } + +window.dialog.message.csd .dialog-action-area button:last-child { border-bottom-right-radius: 7px; } + +filechooser .dialog-action-box { border-top: 1px solid #cdc7c2; } + +filechooser #pathbarbox { border-bottom: 1px solid #f6f5f4; } + +filechooserbutton > button > box { border-spacing: 6px; } + +filechooserbutton:drop(active) { box-shadow: none; border-color: transparent; } + +/*********** Sidebar * */ +.sidebar { background-color: #fbfafa; } + +.sidebar:not(separator):dir(ltr), .sidebar.left:not(separator), .sidebar.left:not(separator):dir(rtl) { border-right: 1px solid #cdc7c2; border-left-style: none; } + +.sidebar:not(separator):dir(rtl), .sidebar.right:not(separator) { border-left: 1px solid #cdc7c2; border-right-style: none; } + +.sidebar listview.view, .sidebar list { background-color: transparent; } + +paned .sidebar.left, paned .sidebar.right, paned .sidebar.left:dir(rtl), paned .sidebar:dir(rtl), paned .sidebar:dir(ltr), paned .sidebar { border-style: none; } + +stacksidebar list.separators:not(.horizontal) > row:not(.separator) { border-bottom: none; } + +stacksidebar row { padding: 10px 4px; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +stacksidebar row { outline: 0 solid transparent; outline-offset: 4px; } + +stacksidebar row:focus:focus-visible { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: -2px; } + +stacksidebar row > label { padding-left: 6px; padding-right: 6px; } + +stacksidebar row.needs-attention > label { background-size: 6px 6px, 0 0; } + +stacksidebar row:selected { background-color: #e8e6e3; border-radius: 5px; color: #2e3436; } + +stacksidebar row:selected:hover:dir(ltr), stacksidebar row:selected:hover:dir(rtl) { background-color: #ddd9d5; } + +stacksidebar row.activatable:active, stacksidebar row.activatable:selected:active { box-shadow: none; } + +separator.sidebar { background-color: #cdc7c2; } + +/********************** Navigation Sidebar * */ +.navigation-sidebar { padding: 5px 0; } + +.navigation-sidebar > separator { margin: 5px; } + +.navigation-sidebar > row { min-height: 36px; padding: 0 8px; border-radius: 5px; margin: 0 5px 2px; transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +.navigation-sidebar > row { outline: 0 solid transparent; outline-offset: 4px; } + +.navigation-sidebar > row:focus-visible:focus-within { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: -2px; } + +.navigation-sidebar > row:hover { background-color: #ddd9d5; } + +.navigation-sidebar > row:selected { background-color: #e8e6e3; color: inherit; } + +.navigation-sidebar > row:selected:hover { background-color: #ddd9d5; } + +.navigation-sidebar > row:disabled { color: #929595; } + +/**************** File chooser * */ +row image.sidebar-icon { opacity: 0.7; } + +/* this should be more generic, only using .navigation-sidebar https://gitlab.gnome.org/GNOME/gtk/-/issues/2929 */ +placessidebar .navigation-sidebar > row { padding: 0; } + +placessidebar .navigation-sidebar > row > revealer { padding: 0 14px; } + +placessidebar .navigation-sidebar > row image.sidebar-icon:dir(ltr) { padding-right: 8px; } + +placessidebar .navigation-sidebar > row image.sidebar-icon:dir(rtl) { padding-left: 8px; } + +placessidebar .navigation-sidebar > row label.sidebar-label:dir(ltr) { padding-right: 2px; } + +placessidebar .navigation-sidebar > row label.sidebar-label:dir(rtl) { padding-left: 2px; } + +button.sidebar-button { min-height: 26px; min-width: 26px; margin-top: 3px; margin-bottom: 3px; padding: 0; border-radius: 100%; } + +placessidebar .navigation-sidebar > row:selected:active { box-shadow: none; } + +placessidebar .navigation-sidebar > row.sidebar-placeholder-row { padding: 0 8px; min-height: 2px; background-image: image(#2ec27e); background-clip: content-box; } + +placessidebar .navigation-sidebar > row.sidebar-new-bookmark-row { color: #3584e4; } + +placessidebar .navigation-sidebar > row:drop(active):not(:disabled) { color: #2ec27e; box-shadow: inset 0 1px #2ec27e, inset 0 -1px #2ec27e; } + +placessidebar .navigation-sidebar > row:drop(active):not(:disabled):selected { color: #ffffff; background-color: #2ec27e; } + +placesview .server-list-button > image { transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -gtk-icon-transform: rotate(0turn); } + +placesview .server-list-button:checked > image { transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); -gtk-icon-transform: rotate(-0.5turn); } + +placesview > actionbar > revealer > box > box { border-spacing: 6px; } + +/********* Paned * */ +paned > separator { min-width: 1px; min-height: 1px; -gtk-icon-source: none; border-style: none; background-color: transparent; background-image: image(#cdc7c2); background-size: 1px 1px; } + +paned > separator:selected { background-image: image(#3584e4); } + +paned > separator.wide { min-width: 5px; min-height: 5px; background-color: #f6f5f4; background-image: image(#cdc7c2), image(#cdc7c2); background-size: 1px 1px, 1px 1px; } + +paned.horizontal > separator { background-repeat: repeat-y; } + +paned.horizontal > separator:dir(ltr) { margin: 0 -8px 0 0; padding: 0 8px 0 0; background-position: left; } + +paned.horizontal > separator:dir(rtl) { margin: 0 0 0 -8px; padding: 0 0 0 8px; background-position: right; } + +paned.horizontal > separator.wide { margin: 0; padding: 0; background-repeat: repeat-y, repeat-y; background-position: left, right; } + +paned.vertical > separator { margin: 0 0 -8px 0; padding: 0 0 8px 0; background-repeat: repeat-x; background-position: top; } + +paned.vertical > separator.wide { margin: 0; padding: 0; background-repeat: repeat-x, repeat-x; background-position: bottom, top; } + +/************** GtkVideo * */ +video { background: black; } + +video image.osd { min-width: 64px; min-height: 64px; border-radius: 32px; } + +/************ Tooltips * */ +tooltip { padding: 6px 10px; border-radius: 8px; box-shadow: none; } + +tooltip.background { background-color: rgba(0, 0, 0, 0.8); background-clip: padding-box; border: 1px solid rgba(255, 255, 255, 0.1); color: white; } + +tooltip > box { border-spacing: 6px; } + +/***************** Color Chooser * */ +colorswatch { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +colorswatch { outline: 0 solid transparent; outline-offset: 6px; } + +colorswatch:focus:focus-visible { outline-color: rgba(53, 132, 228, 0.5); outline-width: 4px; outline-offset: -2px; } + +colorswatch:drop(active), colorswatch { border-style: none; } + +colorswatch.top { border-top-left-radius: 5.5px; border-top-right-radius: 5.5px; } + +colorswatch.top > overlay { border-top-left-radius: 5px; border-top-right-radius: 5px; } + +colorswatch.bottom { border-bottom-left-radius: 5.5px; border-bottom-right-radius: 5.5px; } + +colorswatch.bottom > overlay { border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } + +colorswatch.left, colorswatch:first-child:not(.top) { border-top-left-radius: 5.5px; border-bottom-left-radius: 5.5px; } + +colorswatch.left > overlay, colorswatch:first-child:not(.top) > overlay { border-top-left-radius: 5px; border-bottom-left-radius: 5px; } + +colorswatch.right, colorswatch:last-child:not(.bottom) { border-top-right-radius: 5.5px; border-bottom-right-radius: 5.5px; } + +colorswatch.right > overlay, colorswatch:last-child:not(.bottom) > overlay { border-top-right-radius: 5px; border-bottom-right-radius: 5px; } + +colorswatch.dark > overlay { color: white; } + +colorswatch.dark.activatable:hover > overlay { border-color: rgba(0, 0, 0, 0.8); } + +colorswatch.light > overlay { color: black; } + +colorswatch.light.activatable:hover > overlay { border-color: rgba(0, 0, 0, 0.5); } + +colorswatch:drop(active) { box-shadow: none; } + +colorswatch.light:drop(active) > overlay { border-color: #2ec27e; box-shadow: inset 0 0 0 2px #27a56b, inset 0 0 0 1px #2ec27e; } + +colorswatch.dark:drop(active) > overlay { border-color: #2ec27e; box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.3), inset 0 0 0 1px #2ec27e; } + +colorswatch > overlay { border: 1px solid rgba(0, 0, 0, 0.3); } + +colorswatch.activatable:hover > overlay { box-shadow: inset 0 1px rgba(255, 255, 255, 0.4), inset 0 -1px rgba(0, 0, 0, 0.2); } + +colorswatch#add-color-button { border-radius: 5px 0 0 5px; } + +colorswatch#add-color-button:only-child { border-radius: 5px; } + +colorswatch#add-color-button > overlay { color: #2e3436; outline-color: rgba(53, 132, 228, 0.5); border-color: #cdc7c2; background-image: linear-gradient(to top, #f6f5f4 2px, #fbfafa); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +colorswatch#add-color-button.activatable:hover > overlay { color: #2e3436; border-color: #cdc7c2; background-image: linear-gradient(to top, #d6d1cd, #e8e6e3 1px); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); } + +colorswatch:disabled { opacity: 0.5; } + +colorswatch:disabled > overlay { border-color: rgba(0, 0, 0, 0.6); box-shadow: none; } + +row:selected colorswatch { box-shadow: 0 0 0 2px #ffffff; } + +colorswatch#editor-color-sample { border-radius: 4px; } + +colorswatch#editor-color-sample > overlay { border-radius: 4.5px; } + +plane { transition: outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: outline, outline-width, outline-offset, outline-color; transition-duration: 300ms; animation-timing-function: ease-in-out; } + +plane { outline: 0 solid transparent; outline-offset: 6px; } + +plane:focus:focus-visible { outline-color: rgba(53, 132, 228, 0.5); outline-width: 2px; outline-offset: 2px; } + +colorchooser .popover.osd { border-radius: 5px; } + +/******** Misc * */ +.content-view { background-color: #e6e3e0; } + +.content-view:hover { -gtk-icon-filter: brightness(1.2); } + +.content-view .tile { margin: 2px; background-color: transparent; border-radius: 0; padding: 0; } + +.content-view .tile:active, .content-view .tile:selected { background-color: transparent; } + +.content-view .tile:disabled { background-color: transparent; } + +.osd .scale-popup button.flat { border-style: none; border-radius: 5px; } + +.scale-popup button:hover { background-color: rgba(46, 52, 54, 0.1); border-radius: 5px; } + +/********************** Window Decorations * */ +window { border-width: 0px; } + +window.csd { box-shadow: 0 3px 9px 1px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(0, 0, 0, 0.23); margin: 0px; border-radius: 8px 8px 0 0; } + +window.csd:backdrop { box-shadow: 0 3px 9px 1px transparent, 0 2px 6px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.18); transition: 200ms ease-out; } + +window.csd.popup { border-radius: 5px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.13); } + +window.csd.dialog.message { border-radius: 8px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.13); } + +window.solid-csd { margin: 0; padding: 4px; border: solid 1px #cdc7c2; border-radius: 0; box-shadow: inset 0 0 0 4px #cdc7c2, inset 0 0 0 3px white, inset 0 1px rgba(255, 255, 255, 0.8); } + +window.solid-csd:backdrop { box-shadow: inset 0 0 0 4px #cdc7c2, inset 0 0 0 3px #f6f5f4, inset 0 1px rgba(255, 255, 255, 0.8); } + +window.maximized, window.fullscreen { border-radius: 0; box-shadow: none; } + +window.tiled, window.tiled-top, window.tiled-left, window.tiled-right, window.tiled-bottom { border-radius: 0; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18), 0 0 0 20px transparent; } + +window:backdrop { box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18), 0 0 0 20px transparent; } + +window.popup { box-shadow: none; } + +window.ssd { box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.23); } + +tooltip.csd { border-radius: 5px; box-shadow: none; } + +.view:selected:focus, .view:selected, textview > text:selected:focus, textview > text:selected, textview > text > selection:focus, textview > text > selection, iconview:selected:focus, iconview:selected, flowbox > flowboxchild:selected, gridview > child:selected, entry > text > selection, modelbutton.flat:selected, spinbutton:not(.vertical) > text > selection, spinbutton.vertical > text > text > selection, spinbutton.vertical > text > selection, columnview.view:selected:focus, columnview.view:selected, treeview.view:selected:focus, treeview.view:selected, row:selected, calendar > grid > label.day-number:selected { background-color: #3584e4; } + +label:selected, .view:selected:focus, .view:selected, textview > text:selected:focus, textview > text:selected, textview > text > selection:focus, textview > text > selection, iconview:selected:focus, iconview:selected, flowbox > flowboxchild:selected, gridview > child:selected, entry > text > selection, modelbutton.flat:selected, spinbutton:not(.vertical) > text > selection, spinbutton.vertical > text > text > selection, spinbutton.vertical > text > selection, columnview.view:selected:focus, columnview.view:selected, treeview.view:selected:focus, treeview.view:selected, row:selected, calendar > grid > label.day-number:selected { color: #ffffff; } + +label:disabled > selection, label:disabled:selected, .view:disabled:selected, textview > text:disabled:selected:focus, textview > text:disabled:selected, textview > text > selection:disabled, iconview:disabled:selected:focus, iconview:disabled:selected, flowbox > flowboxchild:disabled:selected, gridview > child:disabled:selected, entry > text > selection:disabled, modelbutton.flat:disabled:selected, spinbutton:not(.vertical) > text > selection:disabled, spinbutton.vertical > text > text > selection:disabled, spinbutton.vertical > text > selection:disabled, columnview.view:disabled:selected, treeview.view:disabled:selected, row:disabled:selected, calendar > grid > label.day-number:disabled:selected { color: #9ac2f2; } + +.monospace { font-family: monospace; } + +/********************** Touch Copy & Paste * */ +cursor-handle { background-color: transparent; background-image: none; box-shadow: none; border-style: none; min-width: 20px; min-height: 24px; padding-left: 20px; padding-right: 20px; padding-top: 24px; padding-bottom: 24px; } + +cursor-handle.top:dir(ltr), cursor-handle.bottom:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/text-select-start.png"), url("assets/text-select-start@2.png")); } + +cursor-handle.bottom:dir(ltr), cursor-handle.top:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/text-select-end.png"), url("assets/text-select-end@2.png")); } + +cursor-handle.insertion-cursor:dir(ltr), cursor-handle.insertion-cursor:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above.png"), url("assets/slider-horz-scale-has-marks-above@2.png")); } + +cursor-handle.top:hover:dir(ltr), cursor-handle.bottom:hover:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/text-select-start-hover.png"), url("assets/text-select-start-hover@2.png")); } + +cursor-handle.bottom:hover:dir(ltr), cursor-handle.top:hover:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/text-select-end-hover.png"), url("assets/text-select-end-hover@2.png")); } + +cursor-handle.insertion-cursor:hover:dir(ltr), cursor-handle.insertion-cursor:hover:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above-hover.png"), url("assets/slider-horz-scale-has-marks-above-hover@2.png")); } + +cursor-handle.top:active:dir(ltr), cursor-handle.bottom:active:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/text-select-start-active.png"), url("assets/text-select-start-active@2.png")); } + +cursor-handle.bottom:active:dir(ltr), cursor-handle.top:active:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/text-select-end-active.png"), url("assets/text-select-end-active@2.png")); } + +cursor-handle.insertion-cursor:active:dir(ltr), cursor-handle.insertion-cursor:active:dir(rtl) { -gtk-icon-source: -gtk-scaled(url("assets/slider-horz-scale-has-marks-above-active.png"), url("assets/slider-horz-scale-has-marks-above-active@2.png")); } + +shortcuts-section { margin: 20px; } + +.shortcuts-search-results { margin: 20px; border-spacing: 24px; } + +shortcut { border-spacing: 6px; } + +shortcut > .keycap { min-width: 20px; min-height: 25px; margin-top: 2px; padding-bottom: 3px; padding-left: 6px; padding-right: 6px; color: #2e3436; background-color: #ffffff; border: 1px solid; border-color: #e1dedb; border-radius: 5px; box-shadow: inset 0 -3px #f8f7f6; font-size: smaller; } + +:not(decoration):not(window):drop(active):focus, :not(decoration):not(window):drop(active) { border-color: #2ec27e; box-shadow: inset 0 0 0 1px #2ec27e; caret-color: #2ec27e; } + +stackswitcher > button.text-button { min-width: 100px; } + +stackswitcher.circular { border-spacing: 12px; } + +stackswitcher.circular > button.circular, stackswitcher.circular > button.text-button.circular { min-width: 32px; min-height: 32px; padding: 0; } + +/************* App Icons * */ +/* Outline for low res icons */ +.lowres-icon { -gtk-icon-shadow: 0 -1px rgba(0, 0, 0, 0.05), 1px 0 rgba(0, 0, 0, 0.1), 0 1px rgba(0, 0, 0, 0.3), -1px 0 rgba(0, 0, 0, 0.1); } + +/* Drapshadow for large icons */ +.icon-dropshadow { -gtk-icon-shadow: 0 1px 12px rgba(0, 0, 0, 0.05), 0 -1px rgba(0, 0, 0, 0.05), 1px 0 rgba(0, 0, 0, 0.1), 0 1px rgba(0, 0, 0, 0.3), -1px 0 rgba(0, 0, 0, 0.1); } + +/********* Emoji * */ +popover.emoji-picker > contents { padding: 0; } + +.emoji-searchbar { padding: 6px; border-spacing: 6px; border-bottom: 1px solid #cdc7c2; } + +.emoji-toolbar { padding: 6px; border-spacing: 6px; border-top: 1px solid #cdc7c2; } + +button.emoji-section { border-color: transparent; border-width: 3px; border-style: none none solid; border-radius: 0; padding: 3px 0 0; min-width: 32px; min-height: 28px; /* reset props inherited from the button style */ background: none; box-shadow: none; text-shadow: none; } + +button.emoji-section:hover { border-color: #cdc7c2; } + +button.emoji-section:checked { border-color: #3584e4; } + +popover.emoji-picker emoji { font-size: x-large; padding: 6px; border-radius: 6px; } + +popover.emoji-picker emoji:focus, popover.emoji-picker emoji:hover { background: #3584e4; } + +emoji-completion-row > box { border-spacing: 10px; padding: 2px 10px; } + +emoji-completion-row:focus, emoji-completion-row:hover { background-color: #3584e4; color: #ffffff; } + +emoji-completion-row emoji:focus, emoji-completion-row emoji:hover { background-color: #e8e6e3; } + +popover.entry-completion > contents { padding: 0; } + +statusbar { padding: 6px 10px 6px 10px; } + +menubutton > button > box { border-spacing: 6px; } + +menubutton arrow { min-height: 16px; min-width: 16px; } + +menubutton arrow.none { -gtk-icon-source: -gtk-icontheme("open-menu-symbolic"); } + +menubutton arrow.down { -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +menubutton arrow.up { -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); } + +menubutton arrow.left { -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); } + +menubutton arrow.right { -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } + +/* GTK NAMED COLORS ---------------- use responsibly! */ +/* +widget text/foreground color */ +@define-color theme_fg_color #2e3436; +/* +text color for entries, views and content in general */ +@define-color theme_text_color black; +/* +widget base background color */ +@define-color theme_bg_color #f6f5f4; +/* +text widgets and the like base background color */ +@define-color theme_base_color #ffffff; +/* +base background color of selections */ +@define-color theme_selected_bg_color #3584e4; +/* +text/foreground color of selections */ +@define-color theme_selected_fg_color #ffffff; +/* +base background color of insensitive widgets */ +@define-color insensitive_bg_color #faf9f8; +/* +text foreground color of insensitive widgets */ +@define-color insensitive_fg_color #929595; +/* +insensitive text widgets and the like base background color */ +@define-color insensitive_base_color #ffffff; +/* +widget text/foreground color on backdrop windows */ +@define-color theme_unfocused_fg_color #929595; +/* +text color for entries, views and content in general on backdrop windows */ +@define-color theme_unfocused_text_color black; +/* +widget base background color on backdrop windows */ +@define-color theme_unfocused_bg_color #f6f5f4; +/* +text widgets and the like base background color on backdrop windows */ +@define-color theme_unfocused_base_color #fcfcfc; +/* +base background color of selections on backdrop windows */ +@define-color theme_unfocused_selected_bg_color #3584e4; +/* +text/foreground color of selections on backdrop windows */ +@define-color theme_unfocused_selected_fg_color #ffffff; +/* +insensitive color on backdrop windows*/ +@define-color unfocused_insensitive_color #d4cfca; +/* +widgets main borders color */ +@define-color borders #cdc7c2; +/* +widgets main borders color on backdrop windows */ +@define-color unfocused_borders #d5d0cc; +/* +these are pretty self explicative */ +@define-color warning_color #f57900; +@define-color error_color #cc0000; +@define-color success_color #33d17a; +/* +these colors are exported for the window manager and shouldn't be used in applications, +read if you used those and something break with a version upgrade you're on your own... */ +@define-color wm_title shade(#2e3436, 1.8); +@define-color wm_unfocused_title #929595; +@define-color wm_highlight rgba(255, 255, 255, 0.8); +@define-color wm_borders_edge rgba(255, 255, 255, 0.8); +@define-color wm_bg_a shade(#f6f5f4, 1.2); +@define-color wm_bg_b #f6f5f4; +@define-color wm_shadow alpha(black, 0.35); +@define-color wm_border alpha(black, 0.18); +@define-color wm_button_hover_color_a shade(#f6f5f4, 1.3); +@define-color wm_button_hover_color_b #f6f5f4; +@define-color wm_button_active_color_a shade(#f6f5f4, 0.85); +@define-color wm_button_active_color_b shade(#f6f5f4, 0.89); +@define-color wm_button_active_color_c shade(#f6f5f4, 0.9); +/* content view background such as thumbnails view in Photos or Boxes */ +@define-color content_view_bg #ffffff; +/* Very contrasty background for text views (@theme_text_color foreground) */ +@define-color text_view_bg #ffffff; diff --cc subprojects/gi-docgen/.gitlab-ci.yml index 0000000000,0000000000..ee3c6355fa new file mode 100644 --- /dev/null +++ b/subprojects/gi-docgen/.gitlab-ci.yml @@@ -1,0 -1,0 +1,66 @@@ ++# SPDX-FileCopyrightText: 2021 GNOME Foundation ++# ++# SPDX-License-Identifier: CC0-1.0 ++ ++stages: ++ - build ++ - check ++ - deploy ++ ++#meson-build: ++# stage: build ++# needs: [] ++# script: ++# - dnf install -y meson ninja-build python3-flake8 python3-mypy python3-markdown python3-jinja2 python3-toml python3-typogrify ++# - meson _build . ++# - meson test -C _build ++# ++#pip-build: ++# stage: build ++# needs: [] ++# script: ++# - dnf install -y python3-pip ++# - python3 -m pip install --user -e . ++ ++.pip: ++ before_script: ++ - export PATH="$HOME/.local/bin:$PATH" ++ - dnf install -y python3-pip ++ ++flake8: ++ stage: check ++ needs: [] ++ script: ++ - dnf install -y python3-flake8 ++ - flake8 --ignore E501,E402,F405,W503 --show-source gidocgen ++ ++mypy: ++ stage: check ++ needs: [] ++ script: ++ - dnf install -y python3-mypy ++ - mypy --ignore-missing-imports --disallow-incomplete-defs gidocgen ++ allow_failure: true ++ ++reuse: ++ extends: .pip ++ stage: check ++ needs: [] ++ script: ++ - pip install --user reuse ++ - reuse lint ++ ++pages: ++ extends: .pip ++ stage: deploy ++ needs: [] ++ script: ++ - pip install --user sphinx sphinx_rtd_theme ++ - cd docs ++ - python3 -m sphinx -b html . _build ++ - mv _build ../public ++ artifacts: ++ paths: ++ - public ++ only: ++ - main diff --cc subprojects/gi-docgen/README.md index 6d77374d33,0000000000..c07e06aea6 mode 100644,000000..100644 --- a/subprojects/gi-docgen/README.md +++ b/subprojects/gi-docgen/README.md @@@ -1,88 -1,0 +1,88 @@@ + + +GI-DocGen: Documentation tool for GObject-based libraries +------------------------------------------------------------------------------- + +GI-DocGen is a document generator for GObject-based libraries. GObject is +the base type system of the GNOME project. GI-Docgen reuses the +introspection data generated by GObject-based libraries to generate the API +reference of these libraries, as well as other ancillary documentation. + +## Installation + +### Running GI-DocGen uninstalled + +You can run GI-DocGen from its repository, by calling: + +``` +./gi-docgen.py +``` + +GI-DocGen will automatically detect this case. + +### Installing GI-DocGen via pip + +To install GI-DocGen, you will need to have the following pieces of software +available on your computer: + + - Python 3.6, or later + - pip + +Run the following command: + +``` +pip3 install --user gi-docgen +``` + +After running the command above, make sure to have the `~/.local/bin` +directory listed in your `$PATH` environment variable. + +To update GI-DocGen, run the following command: + +``` +pip3 install --user --upgrade gi-docgen +``` + +## Usage + +First, read [the GI-DocGen tutorial](https://gnome.pages.gitlab.gnome.org/gi-docgen/tutorial.html). + +The documentation for GI-DocGen is [available online](https://gnome.pages.gitlab.gnome.org/gi-docgen/). + +The `examples` directory in the repository contains simple project files for +various GNOME libraries. + +## Disclaimer + +GI-DocGen is **not** a general purpose documentation tool for C libraries. + +While GI-DocGen can be used to generate API references for most GObject/C +libraries that expose introspection data, its main goal is to generate the +reference for GTK and its immediate dependencies. Any and all attempts at +making this tool more generic, or to cover more use cases, will be weighted +heavily against its primary goal. + +GI-DocGen is still in development. The recommended use of GI-DocGen is to +add it as a sub-project to your [Meson build system](https://mesonbuild.com), +and vendor it when releasing dist archives. + +You should **not** depend on a system-wide installation until GI-DocGen is +declared stable. + +If you need a general purpose documentation tool, I strongly recommend: + + - [HotDoc](https://hotdoc.github.io/) + - [Doxygen](https://www.doxygen.nl/index.html) + - [GTK-Doc](https://gitlab.gnome.org/GNOME/gtk-doc/) + +## Copyright and Licensing terms + +Copyright 2021 GNOME Foundation + +GI-DocGen is released under the terms of the Apache License, version 2.0, or - under the terms of the GNU General Publice License, either version 3.0 or, ++under the terms of the GNU General Public License, either version 3.0 or, +at your option, any later version. diff --cc subprojects/gi-docgen/docs/RELEASING.md index 0000000000,0000000000..7985ea6935 new file mode 100644 --- /dev/null +++ b/subprojects/gi-docgen/docs/RELEASING.md @@@ -1,0 -1,0 +1,21 @@@ ++ ++ ++Release check list ++================== ++ ++- [ ] Collect all changes since the previous tag ++- [ ] Tag the release, using `git tag -s YYYY.N` ++- [ ] Write down all the noteworthy changes in the tag message ++- [ ] Update `twine`: `pip install --upgrade --user twine` ++- [ ] Build a Python dist: `python -m build` ++- [ ] Upload the dist to PyPI: `python -m twine upload dist/*` ++- [ ] Build a Meson dist: `meson setup _build . && meson dist -C _build` ++- [ ] Upload the Meson dist to gnome.org ++- [ ] Clean up the repository: `git clean -xdf` ++- [ ] Bump the version in `meson.build` and `gidocgen/core.py` to `YYYY.N+1` ++- [ ] Push the changes to the repository: `git push origin HEAD` ++- [ ] Push the release tag to the repository: `git push origin YYYY.N` diff --cc subprojects/gi-docgen/docs/attributes.rst index c467b347ca,0000000000..b67625a205 mode 100644,000000..100644 --- a/subprojects/gi-docgen/docs/attributes.rst +++ b/subprojects/gi-docgen/docs/attributes.rst @@@ -1,39 -1,0 +1,42 @@@ +.. SPDX-FileCopyrightText: 2021 GNOME Foundation +.. +.. SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +Introspection attributes +======================== + +GI-DocGen consumes the following attributes found in the introspection data when +generating the API reference for that data. + +Properties +---------- + +The following attributes apply to properties. + +``org.gtk.Property.get`` = ``s`` + Defines the getter method for a given property. The value of the attribute is + the C symbol of the function. + +``org.gtk.Property.set`` = ``s`` + Defines the setter method for a given property. The value of the attribute is + the C symbol of the function. + ++``org.gtk.Property.default`` = ``s`` ++ Defines the default value for a given property. ++ +Methods +------- + +The following attributes apply to methods of a classed type or interface. + +``org.gtk.Method.set_property`` = ``s`` + Defines the property set by the function. The property name must be in + the same type as the method + +``org.gtk.Method.get_property`` = ``s`` + Defines the property retrieved by the function. The property name must + be in the same type as the method + +``org.gtk.Method.signal`` = ``s`` + Defines the signal emitted by the function. The signal name must be + in the same type as the method diff --cc subprojects/gi-docgen/docs/gi-docgen.1 index 36fc14ed74,0000000000..2947c93aa1 mode 100644,000000..100644 --- a/subprojects/gi-docgen/docs/gi-docgen.1 +++ b/subprojects/gi-docgen/docs/gi-docgen.1 @@@ -1,170 -1,0 +1,191 @@@ +\" SPDX-FileCopyrightText: 2021 GNOME Foundation +\" SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later +.TH GI\-DOCGEN "1" "" "gi-docgen 2021.3" "User Commands" +.SH NAME +gi-docgen - a documentation generator using gobject\-introspection +.SH SYNOPSIS +.sp +\fBgi\-docgen\fP COMMAND [OPTION...] GIR_FILE +.SH DESCRIPTION +.sp +GI\-DocGen is a document generator for GObject\-based libraries. GObject +is the base type system of the GNOME project. GI\-DocGen uses the machine +readable introspection data provided by GObject\-based libraries in order +to generate the API reference of these libraries, as well as other +ancillary documentation. +.sp +The main gi\-docgen executable provides various subcommands to access all +its functionality. + +.SH Common options +.sp +All commands have the following options: + +.TP +.B \-\-quiet +do not print details of the current operation +.TP +.B \-\-fatal\-warnings +make warnings fatal errors +.TP +.B \-\-help +print command line help + +.SH The generate command +.sp +The \fBgenerate\fR command provides the main functionality of gi\-docgen. + +.B gi-docgen generate [ +.I OPTIONS +.B ] [ +.I GIR_FILE +.B ] + +.sp +The generate command will parse the given GIR file, as well as its +dependencies, and build an API reference for the namespace it finds +in the introspection data. Projects can use a configuration file to +control aspects of the output, as well as provide additional content +that should be included in the documentation. + +.SS "options:" +.TP +.BI \-\-config\fB= FILE +use the given project configuration file +.TP +.BI \-\-content\-dir\fB= PATH +specify the directory where the content files listed in the project +configuration file can be found +.TP +.BI \-\-templates\-dir\fB= PATH +specify the directory where the templates used to generate the +documentation can be found +.TP +.BI \-\-theme\-name\fB= NAME +specify the template name to be used when generating the documentation, +overriding the project's configuration +.TP +.BI \-\-output\-dir\fB= PATH +create the documentation under the given directory +.TP +.B \-\-no\-namespace\-dir +generate all documentation files directly under the output directory, +instead of creating a directory using the namespace name and version +.TP +.BI \-\-add\-include\-path\fB= PATH +add a directory to the path which the scanner uses to find GIR files. Can +be used multiple times to specify multiple directories +.TP +.BI \-\-section\fB= NAME +generate the documentation only for the given section. Can be used +multiple times to specify multiple sections. The supported sections are +\fIaliases\fR, \fIbitfields\fR, \fIclasses\fR, \fIdomains\fR, \fIenums\fR, +\fIinterfaces\fR, \fIstructs\fR and \fIunions\fR. Special values are \fIall\fR, +meaning all sections (the default); and \fInone\fR, meaning no section +.TP +.B \-\-dry\-run +parse the \fIGIR_FILE\fR without generating the documentation + +.SH The gen-index command +.sp +The \fBgen-index\fR command generates an index of symbols and terms +that can be used to search inside the documentation generated by +gi\-docgen. + +.B gi-docgen gen-index [ +.I OPTIONS +.B ] [ +.I GIR_FILE +.B ] + +.sp +The generated index is a JSON formatted file is called \fIindex.json\fR. + +.SS "options:" +.TP +.BI \-\-config\fB= FILE +use the given project configuration file +.TP +.BI \-\-content\-dir\fB= PATH +specify the directory where the content files listed in the project +configuration file can be found +.TP +.BI \-\-output\-dir\fB= PATH +create the index under the given directory +.TP +.BI \-\-add\-include\-path\fB= PATH +add a directory to the path which the scanner uses to find GIR files. Can +be used multiple times to specify multiple directories +.TP +.B \-\-dry\-run +parse the \fIGIR_FILE\fR without generating the documentation + ++.SH The check command ++.sp ++The \fBcheck\fR command runs a series of checks on the introspection ++file, to verify that public API is properly documented. It can be used ++as part of a test suite. ++ ++.B gi-docgen check [ ++.I OPTIONS ++.B ] [ ++.I GIR_FILE ++.B ] ++ ++.SS "options:" ++.TP ++.BI \-\-config\fB= FILE ++use the given project configuration file ++.TP ++.BI \-\-add\-include\-path\fB= PATH ++add a directory to the path which the scanner uses to find GIR files. Can ++be used multiple times to specify multiple directories ++ +.SH The help command +.sp +The \fBhelp\fR command prints out the command line help. If you don't +specify any command or option when invoking gi\-docgen, the help command +will be implied. + +.B gi-docgen help [ +.I OPTIONS +.B ] [ +.I COMMAND +.B ] + +.sp +If no command is specified, help will print out the list of commands. +.sp +If a command is specified, help will print out the command line help for +that program. + +.SS "options:" +.TP +.B \-\-version +print out the version of gi\-docgen + +.SH EXIT STATUS + +.TP +.B 0 +The command was successful. +.TP +.B 1 +Error, or warning, was generated. + +.SH ENVIRONMENT VARIABLES +.sp +The gi\-docgen executable uses the \fBXDG_DATA_DIRS\fP and \fBXDG_DATA_HOME\fP +environment variables to search for introspection data included in the GIR +file. +.sp +If the \fBGIDOCGEN_DEBUG\fP environment variable is set, gi\-docgen will print +out additional messages, which can be helpful when debugging issues. + +.SH SEE ALSO +.sp +GI\-DocGen: http://gnome.pages.gitlab.gnome.org/gi-docgen/ +.sp +GObject\-Introspection: https://gi.readthedocs.org/ +.sp +GObject: https://developer.gnome.org/gobject/ diff --cc subprojects/gi-docgen/docs/linking.rst index fc2858d2e8,0000000000..1dd596194b mode 100644,000000..100644 --- a/subprojects/gi-docgen/docs/linking.rst +++ b/subprojects/gi-docgen/docs/linking.rst @@@ -1,184 -1,0 +1,209 @@@ +.. SPDX-FileCopyrightText: 2021 GNOME Foundation +.. +.. SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +===================== +Linking items by name +===================== + +Gi-docgen is capable of linking symbols across the same introspected namespace, +by using a qualifier fragment and the symbol name. + +For instance: + +.. code-block:: c + + /** + * ExampleFoo: + * + * This structure is related to [struct@Bar]. + */ + + /** + * example_foo_set_bar: + * + * Sets [struct@Example.Bar] on an instance of `Foo`. + */ + + /** + * ExampleFoo:bar: + * + * Sets an instance of [`Bar`](struct.Bar.html) on `Foo`. + */ + + +will all link to ``Bar``. + +Backticks will be stripped, so ``[`class@Foo`]`` will correctly link to ``Foo``. + +The link can either be a fully qualified name, which includes the namespace; or +a name relative to the current namespace; for instance, both of the following links +will point to ``ExampleFoo`` when generating the documentation for the "Example" +namespace: + +- ``[class@Foo]`` +- ``[class@Example.Foo]`` + +The available qualifier fragments are: + +.. list-table:: - :widths: 15 35 50 ++ :widths: 10 15 25 50 + :header-rows: 1 + + * - Fragment ++ - Argument + - Description + - Example + * - ``alias`` ++ - ``TypeName`` + - An alias to another type + - ``[alias@Allocation]`` + * - ``callback`` ++ - ``TypeName`` + - A callback type + - ``[callback@Gtk.ListBoxForeachFunc]`` + * - ``class`` ++ - ``TypeName`` + - An object class + - ``[class@Widget]``, ``[class@Gdk.Surface]``, ``[class@Gsk.RenderNode]`` + * - ``const`` ++ - ``CONSTANT`` + - A constant or pre-processor symbol + - ``[const@Gdk.KEY_q]`` + * - ``ctor`` ++ - ``TypeName.constructor`` + - A constructor function + - ``[ctor@Gtk.Box.new]``, ``[ctor@Button.new_with_label]`` + * - ``enum`` ++ - ``TypeName`` + - A plain enumeration + - ``[enum@Orientation]`` + * - ``error`` ++ - ``TypeName`` + - A ``GError`` domain enumeration + - ``[error@Gtk.BuilderParseError]`` + * - ``flags`` ++ - ``TypeName`` + - A bitfield + - ``[flags@Gdk.ModifierType]`` + * - ``func`` ++ - ``function``, ``TypeName.function`` + - A global or a type function + - ``[func@Gtk.init]``, ``[func@show_uri]``, ``[func@Gtk.Window.list_toplevels]`` + * - ``iface`` ++ - ``TypeName`` + - A ``GTypeInterface`` + - ``[iface@Gtk.Buildable]`` + * - ``method`` ++ - ``TypeName.method``, ``TypeNameClass.method`` + - An instance or class method + - ``[method@Gtk.Widget.show]``, ``[method@WidgetClass.add_binding]`` + * - ``property`` ++ - ``TypeName:property`` + - A ``GObject`` property + - ``[property@Gtk.Orientable:orientation]`` + * - ``signal`` ++ - ``TypeName::signal`` + - A ``GObject`` signal + - ``[signal@Gtk.RecentManager::changed]`` + * - ``struct`` ++ - ``TypeName`` + - A plain C structure or union + - ``[struct@Gtk.TextIter]`` + * - ``vfunc`` ++ - ``TypeName.virtual`` + - A virtual function in a class or interface + - ``[vfunc@Gtk.Widget.measure]`` ++ * - ``type`` ++ - ``TypeName`` ++ - A registered type ++ - ``[type@Widget]``, ``[type@Gdk.ModifierType]``, ``[type@Gtk.TextIter]`` ++ * - ``id`` ++ - ``function`` ++ - A C symbol ++ - ``[id@gtk_window_new]``, ``[id@g_signal_connect]`` + +The generic ``type`` fragment, followed by a type, will look up the given type +and generate the appropriate link for it. The type can be fully qualified or +relative to the current namespace: + +:: + + // Equivalent to [class@Gtk.Window] + [type@Gtk.Window] + + // Equivalent to [enum@Gtk.Orientation] + [type@Gtk.Orientation] + +Anything that is a known type—aliases, callbacks, classes, constants, +enumerations, interfaces, structures—can be linked using the ``type`` fragment. + +Additionally, the ``id`` fragment, followed by a C symbol identifier, will try +to link to the function; for instance: + +:: + + // Equivalent to [func@Gtk.show_uri], will link to gtk_show_uri() + [id@gtk_show_uri] + + // Equivalent to [method@Gtk.Widget.show], will link to gtk_widget_show() + [id@gtk_widget_show] + - The ``id`` fragment can only be used for symbols within the current namespace. ++ // Equivalent to [func@GObject.signal_emit], will link to g_signal_emit() ++ [id@g_signal_emit] + +It's important to note that the ``method`` and ``func`` fragments can have +multiple meanings: + +- the ``method`` fragment will match both instance and class methods, depending + on the type used; for instance, to match an instance method you should use the + type name, and to match a class method you should use the class name. The class + method should not be confused with the ``vfunc`` fragment, which uses the type + name and links to virtual methods defined in the class or interface structure. + Class methods take the class pointer as their first argument, whereas virtual + methods take the instance pointer as their first argument. + +:: + + // will link to gtk_widget_show() + [method@Gtk.Widget.show] + + // will link to gtk_widget_class_add_binding() + [method@Gtk.WidgetClass.add_binding] + + // will link to GtkWidgetClass.show + [vfunc@Gtk.Widget.show] + + +- similarly, the ``func`` fragment will match global functions and type + functions, depending on whether the link contains a type or not. Additionally, + ``func`` will match function macros, which are part of the global namespace. + +:: + + // will link to gtk_show_uri() + [func@Gtk.show_uri] + + // will link to gtk_window_list_toplevels() + [func@Gtk.Window.list_toplevels] + + // will link to gtk_widget_class_bind_template_child() + [func@Gtk.widget_class_bind_template_child] + +External Links +-------------- + +Gi-docgen can use the same syntax to point to symbols in other namespaces +with gi-docgen-generated documentation, as long as you provide it with +a mapping from the namespace names to a base url for the docs. This is +done by defining a JavaScript map called ``baseURLs`` like this: + +.. code-block:: js + + baseURLs = [ + [ 'Pango', 'https://gnome.pages.gitlab.gnome.org/pango/Pango/' ], + [ 'PangoCairo', 'https://gnome.pages.gitlab.gnome.org/pango/PangoCairo/' ], + ] + +And specifying the path of the JavaScript file into the ``extras`` section +of the project configuration, in the ``urlmap_file`` key. diff --cc subprojects/gi-docgen/docs/project-configuration.rst index 979ac05def,0000000000..9da5c84b9c mode 100644,000000..100644 --- a/subprojects/gi-docgen/docs/project-configuration.rst +++ b/subprojects/gi-docgen/docs/project-configuration.rst @@@ -1,212 -1,0 +1,239 @@@ +.. SPDX-FileCopyrightText: 2021 GNOME Foundation +.. +.. SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +===================== +Project configuration +===================== + +Projects using gi-docgen should provide their own configuration file to describe +how to generate their API reference. + +The configuration file format uses `ToML `__ to provide key +and value pairs that will be used by gi-docgen and, optionally, by the templates +themselves. + +Project configuration takes precendence over gi-docgen's defaults, but can be +overridden by command line options, where applicable. + +Standard sections and keys +-------------------------- + +The ``library`` section +~~~~~~~~~~~~~~~~~~~~~~~ + +The ``library`` section is used to define the library configuration values +that gi-docgen will pass to the templates, as well as configuration switches +that control the files generated by gi-docgen. + +The following keys are used, if found: + +``version`` = ``s`` + The version of the library. This is the actual version of the shared + library, as opposed to the version of the API as represented by the + namespace. + +``authors`` = ``s`` + The name of the authors of the library, as a string. + +``license`` = ``s`` + The license of the documentation, as an `SPDX identifier `__. + +``website_url`` = ``s`` + The website for the library. + +``browse_url`` = ``s`` + The website that can be used to browse the source code of the library. + +``logo_url`` = ``s`` + The location of a logo image. This can be a local file, or a URL. + +``description`` = ``s`` + A short description of the library. + +``dependencies`` = ``dict(s, dict(s, s)`` + A dictionary of dependencies; each entry in the dictionary has a key in the + form of ``{namespace}-{version}``, and values in the form of a dictionary + with the following keys: ``name``, ``description``, and ``docs_url``. + +``devhelp`` = ``b`` + Whether gi-docgen should generate a DevHelp file for the namespace. + +``search_index`` = ``b`` + Whether gi-docgen should generate a search index file for the namespace. + + +The ``theme`` section +~~~~~~~~~~~~~~~~~~~~~ + +The ``theme`` section is used to define the theme being used by gi-docgen when +generating the API reference of a project. + +The following keys are used, if found: + +``templates_dir`` = ``s`` + The directory that contains the templates to be used by gi-docgen. The + default directory is inside the gi-docgen module directory. This key + can be overridden by the ``--templates-dir`` command line argument. + +``name`` = ``s`` + The name of the template to use. The name is a sub-directory of the + ``template_dir`` directory, and will be used to load the template's + configuration file. This key can be overridden by the ``--theme-name`` + command line argument. + +``show_index_summary`` = ``b`` + A boolean value that controls whether to show the summary of each + symbol in the namespace index. + +``show_class_hierarchy`` = ``b`` + A boolean value that controls whether to generate a class graph + with the ancestors of a type, as well as the implemented interfaces. + Requires the ``dot`` utility from `GraphViz `__ + installed in the ``PATH``. + +The ``source-location`` section +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``source-location`` section is used to define the location of the source +code repository of a project to allow gi-docgen to create links from the API +reference to the definition of symbols and the source of the documentation +stanzas. + +The following keys are used, if found: + +``base_url`` = ``s`` + The base URL for accessing a file in the source code repository. + +``file_format`` = ``s`` + The format string used to point to a file, and a line in that file; + the string can contain the token ``{filename}``, which will be replaced + with the basename of the file; and the token ``{line}``, which will be + replaced with the line in the file. The default value for this key + is: ``{filename}#L{line}``. + +The ``extra`` section +~~~~~~~~~~~~~~~~~~~~~ + +The ``extra`` section is used to define additional content used when +generating the API reference of a project. + +The following keys are used, if found: + +``content_files`` = ``list(s)`` + A list of tuples. The first element of the tuple is a Markdown - file name, relative to the directory specified by the ``--content-dir`` - command line argument; the second element of the tuple is the ++ file name, relative to the directories specified by the ``--content-dir`` ++ command line arguments; the second element of the tuple is the + title used for the link to the content file. When generating the + API reference, gi-docgen will transform the Markdown file into + an HTML one, using the same pre-processing filters applied to the + documentation blocks found in the introspection data. The + generated HTML files will be placed in the root directory of + the namespace. + +``content_images`` = ``list(s)`` - A list of files, relative to the directory specified by the - ``--content-dir`` command line argument. The files will be copied ++ A list of files, relative to the directories specified by the ++ ``--content-dir`` command line arguments. The files will be copied + in the root directory of the namespace. + +``urlmap_file`` = ``s`` + Path of a JavaScript file that defines the mapping from namespaces + to url prefixes for resolving links to external symbols, as a + JavaScript map with the name `baseURLs`: + +:: + + baseURLs = [ + [ 'Pango', 'https://gnome.pages.gitlab.gnome.org/pango/Pango/' ], + [ 'PangoCairo', 'https://gnome.pages.gitlab.gnome.org/pango/PangoCairo/' ], + ] + + +Symbol overrides +---------------- + +Visibility +~~~~~~~~~~ + +It is possible to override the visibility of types, properties, and symbols in +the introspection data from within the project configuration file. + +The following example will hide the type ``Protected``: + +:: + + [[object]] + name = "Protected" + hidden = true + +The type will be skipped when generating the API reference and the search index. +This annotation applies to all possible top-level types: + + - aliases + - bitfields + - callbacks + - classes + - domains + - enums + - functions + - function macros + - interfaces + - records + - unions + ++The ``object`` key is always an array of dictionaries; each element in the array ++can have a ``name`` key, used to match the object name exactly; or a ``pattern`` ++key, which uses a regular expression to match the object name. ++ ++Each object can contain the following keys: ++ ++ - ``name``: the name of the symbol to match exactly ++ - ``pattern``: a regular expression to match the symbol name ++ - ``hidden``: whether the symbol should be hidden from the documentation ++ - ``check_ignore``: whether the symbol should be skipped when checking the ++ documentation ++ ++Each element can also have the following sections: ++ ++ - ``property`` ++ - ``signal`` ++ - ``constructor`` ++ - ``method`` ++ - ``function`` ++ ++Each one of these sections can contain array of objects. ++ +The following example will hide the ``backend`` property on the ``Printer`` type: + +:: + + [[object]] + name = "Printer" + + [[object.property]] + name = "backend" + hidden = true + +The following example will hide the ``private-changed`` signal on the +``StyleProvider`` type: + +:: + + [[object]] + name = "StyleProvider" + + [[object.signal]] + name = "private-changed" + hidden = true + - The ``object`` key is always an array of dictionaries; each element in the array - has a ``name`` key, used to match it; it can also have a ``property`` and a - ``signal`` keys, each containing an array of dictionaries with a ``name`` key. ++The following example will skip the ``quark`` function on the ``ParserError`` ++type when checking the documentation: ++ ++:: ++ ++ [[object]] ++ name = "ParserError" + - The ``hidden`` key can be used in both an ``object`` element, or in the - ``property`` and ``signal`` elements. ++ [[object.function]] ++ name = "quark" ++ check_ignore = true diff --cc subprojects/gi-docgen/docs/tools/check.rst index 0000000000,0000000000..6c6a065d5d new file mode 100644 --- /dev/null +++ b/subprojects/gi-docgen/docs/tools/check.rst @@@ -1,0 -1,0 +1,35 @@@ ++.. SPDX-FileCopyrightText: 2021 GNOME Foundation ++.. ++.. SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later ++ ++=============== ++gi-docgen check ++=============== ++ ++Check the documentation in the introspection data ++------------------------------------------------- ++ ++SYNOPSIS ++======== ++ ++**gi-docgen check** [OPTIONS...] [GIRFILE] ++ ++DESCRIPTION ++=========== ++ ++The **check** command runs a series of checks on the introspection ++file, to verify that public API is properly documented. It can be used ++as part of a test suite. ++ ++OPTIONS ++======= ++ ++``--add-include--path DIR`` ++ Adds ``DIR`` to the list of paths used to find introspection data ++ files included in the given ``GIRFILE``. The default search path ++ for GIR files is ``$XDG_DATA_DIRS/gir-1.0`` and ``$XDG_DATA_HOME/gir-1.0``; ++ this option is typically used to include uninstalled GIR files, or ++ non-standard locations. ++ ++``-C, --config FILE`` ++ Loads a project configuration file. diff --cc subprojects/gi-docgen/docs/tools/gen-index.rst index 5525221882,0000000000..5882ac02b7 mode 100644,000000..100644 --- a/subprojects/gi-docgen/docs/tools/gen-index.rst +++ b/subprojects/gi-docgen/docs/tools/gen-index.rst @@@ -1,110 -1,0 +1,113 @@@ +.. SPDX-FileCopyrightText: 2021 GNOME Foundation +.. +.. SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +=================== +gi-docgen gen-index +=================== + +Generating the symbols index from introspection data +---------------------------------------------------- + +SYNOPSIS +======== + +**gi-docgen gen-index** [OPTIONS...] [GIRFILE] + +DESCRIPTION +=========== + +The **gen-index** command generates a symbols index from introspection +data. The symbols index can be used to efficiently search symbols and +terms. + +The generated index file is called ``index.json`` + +OPTIONS +======= + +``--add-include--path DIR`` + Adds ``DIR`` to the list of paths used to find introspection data + files included in the given ``GIRFILE``. The default search path + for GIR files is ``$XDG_DATA_DIRS/gir-1.0`` and ``$XDG_DATA_HOME/gir-1.0``; + this option is typically used to include uninstalled GIR files, or + non-standard locations. + +``-C, --config FILE`` + Loads a project configuration file. + +``--dry-run`` + Only load the introspection data, without generating the index. + +``--content-dir DIR`` - The directory for extra content, like additional files and images - specified in the project configuration file. ++ The directories for extra content, like additional files and images ++ specified in the project configuration file. This argument may be ++ called multiple times to specify several lookup directories, the ++ content files will be looked these directories in the same order ++ they are added. + +``--output-dir DIR`` + Generates the index file under ``DIR``. + +INDEX FILE +========== + +The index file is in `JSON format `__. + +The index file contains a single object with the following members: + +``meta`` = ``object`` + An object with metadata about the index. + +``symbols`` = ``array of objects`` + An array of all the addressable symbols. + +``terms`` = ``object`` + A dictionary of all terms. + +The ``meta`` object contains the following members: + +``ns`` = ``s`` + The namespace name. + +``version`` = ``s`` + The namespace version. + +``generator`` = ``s`` + The ``gi-docgen`` string. + +``generator-version`` = ``s`` + The version of ``gi-docgen``. + +The ``symbols`` array contains objects with the following members: + +``type`` = ``s`` (*mandatory*) + The type of symbol: ``alias``, ``bitfield``, ``callback``, ``class``, + ``class_method``, ``ctor``, ``domain``, ``enum``, ``function``, + ``function_macro``, ``interface``, ``method``, ``property``, ``signal``, + ``type_func``, ``union``, ``vfunc``. + +``name`` = ``s`` (*mandatory*) + The name of the symbol. + +``ctype`` = ``s`` + The base C type for identifiers; only available for types: ``alias``, + ``bitfield``, ``class``, ``domain``, ``enum``, ``interface``, + ``union``. + +``type_name`` = ``s`` + The type name related to a symbol; only available for types: + ``class_method``, ``ctor``, ``method``, ``property``, ``signal``, + ``type_func``, ``vfunc``. + +``ident`` = ``s`` + The C identifier for symbols; only available for types: + ``class_method``, ``constant``, ``ctor``, ``function``, ``function_macro``, + ``method``, ``type_func``. + +``struct_for`` = ``s`` + The C type related to a class structure; only available for the + ``class_method`` type. + +The ``terms`` dictonary contains all terms as members; each term is associated +to an array of indices in the ``symbols`` array. diff --cc subprojects/gi-docgen/docs/tools/generate.rst index b36f22b6ff,0000000000..146d3e35f1 mode 100644,000000..100644 --- a/subprojects/gi-docgen/docs/tools/generate.rst +++ b/subprojects/gi-docgen/docs/tools/generate.rst @@@ -1,66 -1,0 +1,69 @@@ +.. SPDX-FileCopyrightText: 2021 GNOME Foundation +.. +.. SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +================== +gi-docgen generate +================== + +Generating the API reference from introspection data +---------------------------------------------------- + +SYNOPSIS +======== + +**gi-docgen generate** [OPTIONS...] [GIRFILE] + +DESCRIPTION +=========== + +The **generate** command generates the API reference from a GIR file. + +GIR files are XML files that describe an API in a machine readable way, +and are typically provided by a GObject library. + +OPTIONS +======= + +``--add-include--path DIR`` + Adds ``DIR`` to the list of paths used to find introspection data + files included in the given ``GIRFILE``. The default search path + for GIR files is ``$XDG_DATA_DIRS/gir-1.0`` and ``$XDG_DATA_HOME/gir-1.0``; + this option is typically used to include uninstalled GIR files, or + non-standard locations. + +``-C, --config FILE`` + Loads a project configuration file. + +``--dry-run`` + Only load the introspection data, without generating the reference. + +``--templates-dir DIR`` + Look for templates under ``DIR``. The default location for the + templates directory is inside the ``gi-docgen`` installation. + +``--content-dir DIR`` - The directory for extra content, like additional files and images - specified in the project configuration file. ++ The directories for extra content, like additional files and images ++ specified in the project configuration file. This argument may be ++ called multiple times to specify several lookup directories, content ++ files will be looked up in the content directories in the ++ same order they are added. + +``--theme-name NAME`` + The name of the template to use. Overrides the name specified by + the project configuration file. + +``--output-dir DIR`` + Generates the reference under ``DIR``. + +``--no-namespace-dir`` + When specified, the files are directly generated under the output + directory, instead of using a sub-directory based on the namespace + name and version. + +``--section NAME`` + Only generate the section ``NAME`` of the reference. Valid section + names are: ``aliases``, ``bitfields``, ``callbacks``, ``classes``, + ``constants``, ``domains``, ``enums``, ``functions``, ``function_macros``, + ``interfaces``, ``structs``, and ``unions``. Additionally, ``all`` + will generate all sections, and ``none`` will generate no section. diff --cc subprojects/gi-docgen/docs/tools/index.rst index e52da635fd,0000000000..5508dc2527 mode 100644,000000..100644 --- a/subprojects/gi-docgen/docs/tools/index.rst +++ b/subprojects/gi-docgen/docs/tools/index.rst @@@ -1,70 -1,0 +1,74 @@@ +.. SPDX-FileCopyrightText: 2021 GNOME Foundation +.. +.. SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +======== +Commands +======== + +.. toctree:: + :hidden: + :titlesonly: + :maxdepth: 1 + + generate + gen-index ++ check + +SYNOPSIS +======== + +**gi-docgen** COMMAND [OPTIONS...] + +The ``gi-docgen`` command line utility has several commands, each with its +own functionality and options. + +COMMANDS +======== + +:doc:`generate` + Generates the API reference + +:doc:`gen-index` + Generates the symbol indices for search - ++ ++:doc:`check` ++ Checks the documentation ++ +OPTIONS +======= + +All commands support the following options: + +``-q, --quiet`` + Do not emit any additional information message. + +``--fatal-warnings`` + Make all warnings fatal, immediately terminating the process. + +``--help`` + Show an help message. + +ENVIRONMENT VARIABLES +===================== + +All commands support the following environment variables: + +``GIDOCGEN_DEBUG`` + If set, ``gi-docgen`` will emit debugging messages. + + +BUGS +==== + +Report bugs at https://gitlab.gnome.org/GNOME/gi-docgen/issues + +HOMEPAGE and CONTACT +==================== + +https://gnome.pages.gitlab.gnome.org/gi-docgen/ + +AUTHOR +====== + +Emmanuele Bassi diff --cc subprojects/gi-docgen/gidocgen/config.py index eba2cafa33,0000000000..3da1709be8 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/config.py +++ b/subprojects/gi-docgen/gidocgen/config.py @@@ -1,279 -1,0 +1,297 @@@ +# SPDX-FileCopyrightText: 2021 GNOME Foundation +# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +import os ++import re +import toml + +from urllib.parse import urljoin + +from . import log, utils + + +class GIDocConfig: + """Load and represent the configuration for gidocgen""" + def __init__(self, config_file=None): + self._config_file = config_file + + self._config = {} + if self._config_file is not None: + try: + log.debug(f"Reading configuration file: {self._config_file}") + self._config = toml.load(self._config_file) + except toml.TomlDecodeError as err: + log.error(f"Invalid configuration file: {self._config_file}: {err}") + + @property + def library(self): + return self._config.get('library', {}) + + @property + def extra(self): + return self._config.get('extra', {}) + + @property + def theme(self): + return self._config.get('theme', {}) + + def get_templates_dir(self, default=None): + return self.theme.get('templates_dir', default) + + def get_theme_name(self, default=None): + return self.theme.get('name', default) + + def get_library_name(self, default=None): + return self.library.get('name', default) + + def get_website_url(self, default=None): + return self.library.get('website_url', default) + + def get_logo_url(self, default=None): + return self.library.get('logo_url', default) + + def get_description(self, default=None): + return self.library.get('description', default) + + @property + def urlmap_file(self): + return self.extra.get('urlmap_file') + + @property + def version(self): + return self.library.get('version', 'Unknown') + + @property + def authors(self): + return self.library.get('authors', 'Unknown authors') + + @property + def license(self): + return self.library.get('license', 'All rights reserved') + + @property + def website_url(self): + return self.library.get('website_url', '') + + @property + def browse_url(self): + return self.library.get('browse_url', '') + + @property + def logo_url(self): + return self.library.get('logo_url', '') + + @property + def description(self): + return self.library.get('description', '') + + @property + def dependencies(self): + library = self._config.get('library', None) + if library is None: + return {} + + retval = {} + dependencies = self._config.get('dependencies', {}) + for gir_name, dep in dependencies.items(): + res = {} + res['name'] = dep.get('name', 'Unknown') + res['description'] = dep.get('description', 'No description provided') + res['docs_url'] = dep.get('docs_url', '#') + retval[gir_name] = res + log.debug(f"Found dependency {gir_name}: {res}") + + return retval + + @property + def devhelp(self): + return self.library.get('devhelp', False) + + @property + def search_index(self): + return self.library.get('search_index', False) + + @property + def content_files(self): + return self.extra.get('content_files', []) + + @property + def content_images(self): + return self.extra.get('content_images', []) + + @property + def source_location_url(self): + source_location = self._config.get('source-location', {}) + return source_location.get('base_url', '') + + @property + def file_format(self): + source_location = self._config.get('source-location', {}) + return source_location.get('file_format', '{filename}#L{line}') + + @property + def theme_name(self): + return self.theme.get('name', '') + + @property + def show_index_summary(self): + return self.theme.get('show_index_summary', False) + + @property + def show_class_hierarchy(self): + if utils.find_program('dot') is None: + return False + return self.theme.get('show_class_hierarchy', False) + + def source_link(self, *args): + (filename, line) = args[0] + base_url = self.source_location_url + file_format = self.file_format + endpoint = file_format.replace('{filename}', filename) + endpoint = endpoint.replace('{line}', str(line)) + return urljoin(base_url, endpoint) + + @property + def objects(self): + return self._config.get('object', {}) + - def is_hidden(self, name, category=None, key=None): ++ def match_object(self, name, match_key, category=None, key=None): ++ def obj_matches(obj, name): ++ n = obj.get('name') ++ p = obj.get('pattern') ++ if n is not None and n == name: ++ return True ++ elif p is not None and re.match(p, name): ++ return True ++ return False + for obj in self.objects: - if obj['name'] == name: ++ if obj_matches(obj, name): + if category is None: - return obj.get('hidden', False) ++ return obj.get(match_key, False) + else: - obj_category = obj.get(category) - if obj_category is None: - return False - for c in obj_category: - if c['name'] == key: - return c.get('hidden', False) ++ assert key is not None ++ obj_category = obj.get(category) ++ if obj_category is None: ++ return False ++ for c in obj_category: ++ if obj_matches(c, key): ++ return c.get(match_key, False) + return False + ++ def is_hidden(self, name, category=None, key=None): ++ return self.match_object(name, 'hidden', category, key) ++ ++ def is_skipped(self, name, category=None, key=None): ++ if self.is_hidden(name, category, key): ++ return True ++ return self.match_object(name, 'check_ignore', category, key) ++ + +class GITemplateConfig: + """Load and represent the template configuration""" + def __init__(self, templates_dir, template_name): + self._templates_dir = templates_dir + self._template_name = template_name + self._config_file = os.path.join(templates_dir, template_name, f"{template_name}.toml") + + self._config = {} + try: + log.debug(f"Reading template configuration file: {self._config_file}") + self._config = toml.load(self._config_file) + except toml.TomlDecodeError as err: + log.error(f"Invalid template configuration file: {self._config_file}: {err}") + + @property + def name(self): + metadata = self._config.get('metadata', {}) + return metadata.get('name', self._template_name) + + @property + def css(self): + css = self._config.get('css', {}) + return css.get('style', None) + + @property + def extra_files(self): + extra = self._config.get('extra_files', {}) + return extra.get('files', []) + + @property + def templates(self): + return self._config.get('templates', {}) + + @property + def class_template(self): + return self.templates.get('class', 'class.html') + + @property + def method_template(self): + return self.templates.get('method', 'method.html') + + @property + def class_method_template(self): + return self.templates.get('class_method', 'class_method.html') + + @property + def vfunc_template(self): + return self.templates.get('vfunc', 'vfunc.html') + + @property + def property_template(self): + return self.templates.get('property', 'property.html') + + @property + def signal_template(self): + return self.templates.get('signal', 'signal.html') + + @property + def type_func_template(self): + return self.templates.get('type_func', 'type_func.html') + + @property + def ctor_template(self): + return self.templates.get('ctor', 'type_func.html') + + @property + def func_template(self): + return self.templates.get('function', 'function.html') + + @property + def constant_template(self): + return self.templates.get('constant', 'constant.html') + + @property + def interface_template(self): + return self.templates.get('interface', 'interface.html') + + @property + def namespace_template(self): + return self.templates.get('namespace', 'namespace.html') + + @property + def content_template(self): + return self.templates.get('content', 'content.html') + + @property + def enum_template(self): + return self.templates.get('enum', 'enum.html') + + @property + def flags_template(self): + return self.templates.get('flags', 'flags.html') + + @property + def error_template(self): + return self.templates.get('error', 'error.html') + + @property + def record_template(self): + return self.templates.get('record', 'record.html') + + @property + def union_template(self): + return self.templates.get('union', 'union.html') + + @property + def alias_template(self): + return self.templates.get('alias', 'alias.html') diff --cc subprojects/gi-docgen/gidocgen/core.py index c02346b034,0000000000..b1e3ae6ebe mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/core.py +++ b/subprojects/gi-docgen/gidocgen/core.py @@@ -1,4 -1,0 +1,4 @@@ +# SPDX-FileCopyrightText: 2020 GNOME Foundation +# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + - version = "2021.6" ++version = "2021.9" diff --cc subprojects/gi-docgen/gidocgen/gdcheck.py index 0000000000,0000000000..73d29f0f09 new file mode 100644 --- /dev/null +++ b/subprojects/gi-docgen/gidocgen/gdcheck.py @@@ -1,0 -1,0 +1,371 @@@ ++# SPDX-FileCopyrightText: 2021 GNOME Foundation ++# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later ++ ++import argparse ++import sys ++ ++from . import config, gir, log, utils ++ ++ ++HELP_MSG = "Checks introspection data for valid documentation" ++ ++ ++def _check_doc_element(path, symbol, results): ++ name = '.'.join(path + [symbol.name]) ++ ++ if symbol.source_position is not None: ++ filename = symbol.source_position[0] ++ line = symbol.source_position[1] ++ else: ++ filename = "" ++ line = 0 ++ ++ if symbol.doc is None: ++ results.append(f"Symbol '{name}' at {filename}:{line} is not documented") ++ ++ ++def _check_arg_docs(path, arguments, results): ++ symbol = '.'.join(path) ++ for arg in arguments: ++ if arg.doc is None: ++ results.append(f"Parameter '{arg.name}' of symbol '{symbol}' is not documented") ++ ++ ++def _check_retval_docs(path, retval, results): ++ if retval is None: ++ return ++ ++ if isinstance(retval.target, gir.VoidType): ++ return ++ ++ symbol = '.'.join(path) ++ if retval.doc is None: ++ results.append(f"Return value for symbol '{symbol}' is not documented") ++ ++ ++def _check_aliases(config, repository, symbols, results): ++ for alias in symbols: ++ if config.is_skipped(alias.name): ++ log.debug(f"Skipping hidden alias {alias.name}") ++ continue ++ _check_doc_element([repository.namespace.name], alias, results) ++ ++ ++def _check_bitfields(config, repository, symbols, results): ++ for bitfield in symbols: ++ if config.is_skipped(bitfield.name): ++ log.debug(f"Skipping hidden bitfield {bitfield.name}") ++ continue ++ ++ _check_doc_element([repository.namespace.name], bitfield, results) ++ ++ for member in bitfield.members: ++ _check_doc_element([repository.namespace.name, bitfield.name], member, results) ++ ++ for func in bitfield.functions: ++ if config.is_skipped(bitfield.name, 'function', func.name): ++ continue ++ _check_doc_element([repository.namespace.name, bitfield.name], func, results) ++ _check_arg_docs([repository.namespace.name, bitfield.name, func.name], func.parameters, results) ++ _check_retval_docs([repository.namespace.name, bitfield.name, func.name], func.return_value, results) ++ ++ ++def _check_callbacks(config, repository, symbols, results): ++ for cb in symbols: ++ if config.is_skipped(cb.name): ++ log.debug(f"Skipping hidden callback {cb.name}") ++ continue ++ ++ _check_doc_element([repository.namespace.name], cb, results) ++ _check_arg_docs([repository.namespace.name, cb.name], cb.parameters, results) ++ _check_retval_docs([repository.namespace.name, cb.name], cb.return_value, results) ++ ++ ++def _check_classes(config, repository, symbols, results): ++ for cls in symbols: ++ if config.is_skipped(cls.name): ++ log.debug(f"Skipping hidden class {cls.name}") ++ continue ++ ++ _check_doc_element([repository.namespace.name], cls, results) ++ ++ for ctor in cls.constructors: ++ if config.is_skipped(cls.name, 'constructor', ctor.name): ++ continue ++ _check_doc_element([repository.namespace.name, cls.name], ctor, results) ++ _check_arg_docs([repository.namespace.name, cls.name, ctor.name], ctor.parameters, results) ++ _check_retval_docs([repository.namespace.name, cls.name, ctor.name], ctor.return_value, results) ++ ++ for method in cls.methods: ++ if config.is_skipped(cls.name, 'method', method.name): ++ continue ++ _check_doc_element([repository.namespace.name, cls.name], method, results) ++ _check_arg_docs([repository.namespace.name, cls.name, method.name], method.parameters, results) ++ _check_retval_docs([repository.namespace.name, cls.name, method.name], method.return_value, results) ++ ++ for func in cls.functions: ++ if config.is_skipped(cls.name, 'function', func.name): ++ continue ++ _check_doc_element([repository.namespace.name, cls.name], func, results) ++ _check_arg_docs([repository.namespace.name, cls.name, func.name], func.parameters, results) ++ _check_retval_docs([repository.namespace.name, cls.name, func.name], func.return_value, results) ++ ++ for prop in cls.properties.values(): ++ if config.is_skipped(cls.name, 'property', prop.name): ++ continue ++ _check_doc_element([repository.namespace.name, cls.name], prop, results) ++ ++ for signal in cls.signals.values(): ++ if config.is_skipped(cls.name, 'signal', signal.name): ++ continue ++ _check_doc_element([repository.namespace.name, cls.name], signal, results) ++ _check_arg_docs([repository.namespace.name, cls.name, signal.name], signal.parameters, results) ++ _check_retval_docs([repository.namespace.name, cls.name, signal.name], signal.return_value, results) ++ ++ ++def _check_constants(config, repository, symbols, results): ++ for constant in symbols: ++ if config.is_skipped(constant.name): ++ log.debug(f"Skipping hidden constant {constant.name}") ++ continue ++ ++ _check_doc_element([repository.namespace.name], constant, results) ++ ++ ++def _check_domains(config, repository, symbols, results): ++ for domain in symbols: ++ if config.is_skipped(domain.name): ++ log.debug(f"Skipping hidden error domain {domain.name}") ++ continue ++ ++ _check_doc_element([repository.namespace.name], domain, results) ++ ++ for member in domain.members: ++ _check_doc_element([repository.namespace.name, domain.name], member, results) ++ ++ for func in domain.functions: ++ if config.is_skipped(domain.name, 'function', func.name): ++ continue ++ _check_doc_element([repository.namespace.name, domain.name], func, results) ++ _check_arg_docs([repository.namespace.name, domain.name, func.name], func.parameters, results) ++ _check_retval_docs([repository.namespace.name, domain.name, func.name], func.return_value, results) ++ ++ ++def _check_enums(config, repository, symbols, results): ++ for enum in symbols: ++ if config.is_skipped(enum.name): ++ log.debug(f"Skipping hidden enumeration {enum.name}") ++ continue ++ ++ _check_doc_element([repository.namespace.name], enum, results) ++ ++ for member in enum.members: ++ _check_doc_element([repository.namespace.name, enum.name], member, results) ++ ++ for func in enum.functions: ++ if config.is_skipped(enum.name, 'function', func.name): ++ continue ++ _check_doc_element([repository.namespace.name, enum.name], func, results) ++ _check_arg_docs([repository.namespace.name, enum.name, func.name], func.parameters, results) ++ _check_retval_docs([repository.namespace.name, enum.name, func.name], func.return_value, results) ++ ++ ++def _check_functions(config, repository, symbols, results): ++ for func in symbols: ++ if config.is_skipped(func.name): ++ log.debug(f"Skipping hidden function {func.name}") ++ continue ++ ++ _check_doc_element([repository.namespace.name], func, results) ++ _check_arg_docs([repository.namespace.name, func.name], func.parameters, results) ++ _check_retval_docs([repository.namespace.name, func.name], func.return_value, results) ++ ++ ++def _check_function_macros(config, repository, symbols, results): ++ for func in symbols: ++ if config.is_skipped(func.name): ++ log.debug(f"Skipping hidden function macro {func.name}") ++ continue ++ ++ _check_doc_element([repository.namespace.name], func, results) ++ _check_arg_docs([repository.namespace.name, func.name], func.parameters, results) ++ _check_retval_docs([repository.namespace.name, func.name], func.return_value, results) ++ ++ ++def _check_interfaces(config, repository, symbols, results): ++ for iface in symbols: ++ if config.is_skipped(iface.name): ++ log.debug(f"Skipping hidden interface {iface.name}") ++ continue ++ ++ _check_doc_element([repository.namespace.name], iface, results) ++ ++ for method in iface.methods: ++ if config.is_skipped(iface.name, 'method', method.name): ++ continue ++ _check_doc_element([repository.namespace.name, iface.name], method, results) ++ _check_arg_docs([repository.namespace.name, iface.name, method.name], method.parameters, results) ++ _check_retval_docs([repository.namespace.name, iface.name, method.name], method.return_value, results) ++ ++ for func in iface.functions: ++ if config.is_skipped(iface.name, 'function', func.name): ++ continue ++ _check_doc_element([repository.namespace.name, iface.name], func, results) ++ _check_arg_docs([repository.namespace.name, iface.name, func.name], func.parameters, results) ++ _check_retval_docs([repository.namespace.name, iface.name, func.name], func.return_value, results) ++ ++ for prop in iface.properties.values(): ++ if config.is_skipped(iface.name, 'property', prop.name): ++ continue ++ _check_doc_element([repository.namespace.name, iface.name], prop, results) ++ ++ for signal in iface.signals.values(): ++ if config.is_skipped(iface.name, 'signal', signal.name): ++ continue ++ _check_doc_element([repository.namespace.name, iface.name], signal, results) ++ _check_arg_docs([repository.namespace.name, iface.name, signal.name], signal.parameters, results) ++ _check_retval_docs([repository.namespace.name, iface.name, signal.name], signal.return_value, results) ++ ++ ++def _check_records(config, repository, symbols, results): ++ for struct in symbols: ++ if config.is_skipped(struct.name): ++ log.debug(f"Skipping hidden record {struct.name}") ++ continue ++ ++ _check_doc_element([repository.namespace.name], struct, results) ++ ++ for ctor in struct.constructors: ++ if config.is_skipped(struct.name, 'constructor', ctor.name): ++ continue ++ _check_doc_element([repository.namespace.name, struct.name], ctor, results) ++ _check_arg_docs([repository.namespace.name, struct.name, ctor.name], ctor.parameters, results) ++ _check_retval_docs([repository.namespace.name, struct.name, ctor.name], ctor.return_value, results) ++ ++ for method in struct.methods: ++ if config.is_skipped(struct.name, 'method', method.name): ++ continue ++ _check_doc_element([repository.namespace.name, struct.name], method, results) ++ _check_arg_docs([repository.namespace.name, struct.name, method.name], method.parameters, results) ++ _check_retval_docs([repository.namespace.name, struct.name, method.name], method.return_value, results) ++ ++ for func in struct.functions: ++ if config.is_skipped(struct.name, 'function', func.name): ++ continue ++ _check_doc_element([repository.namespace.name, struct.name], func, results) ++ _check_arg_docs([repository.namespace.name, struct.name, func.name], func.parameters, results) ++ _check_retval_docs([repository.namespace.name, struct.name, func.name], func.return_value, results) ++ ++ ++def _check_unions(config, repository, symbols, results): ++ for union in symbols: ++ if config.is_skipped(union.name): ++ log.debug(f"Skipping hidden union {union.name}") ++ continue ++ ++ _check_doc_element([repository.namespace.name], union, results) ++ ++ for ctor in union.constructors: ++ if config.is_skipped(union.name, 'constructor', ctor.name): ++ continue ++ _check_doc_element([repository.namespace.name, union.name], ctor, results) ++ _check_arg_docs([repository.namespace.name, union.name, ctor.name], ctor.parameters, results) ++ _check_retval_docs([repository.namespace.name, union.name, ctor.name], ctor.return_value, results) ++ ++ for method in union.methods: ++ if config.is_skipped(union.name, 'method', method.name): ++ continue ++ _check_doc_element([repository.namespace.name, union.name], method, results) ++ _check_arg_docs([repository.namespace.name, union.name, method.name], method.parameters, results) ++ _check_retval_docs([repository.namespace.name, union.name, method.name], method.return_value, results) ++ ++ for func in union.functions: ++ if config.is_skipped(union.name, 'function', func.name): ++ continue ++ _check_doc_element([repository.namespace.name, union.name], func, results) ++ _check_arg_docs([repository.namespace.name, union.name, func.name], func.parameters, results) ++ _check_retval_docs([repository.namespace.name, union.name, func.name], func.return_value, results) ++ ++ ++def check(repository, config): ++ namespace = repository.namespace ++ ++ symbols = { ++ "aliases": sorted(namespace.get_aliases(), key=lambda alias: alias.name.lower()), ++ "bitfields": sorted(namespace.get_bitfields(), key=lambda bitfield: bitfield.name.lower()), ++ "callbacks": sorted(namespace.get_callbacks(), key=lambda callback: callback.name.lower()), ++ "classes": sorted(namespace.get_classes(), key=lambda cls: cls.name.lower()), ++ "constants": sorted(namespace.get_constants(), key=lambda const: const.name.lower()), ++ "domains": sorted(namespace.get_error_domains(), key=lambda domain: domain.name.lower()), ++ "enums": sorted(namespace.get_enumerations(), key=lambda enum: enum.name.lower()), ++ "functions": sorted(namespace.get_functions(), key=lambda func: func.name.lower()), ++ "function_macros": sorted(namespace.get_effective_function_macros(), key=lambda func: func.name.lower()), ++ "interfaces": sorted(namespace.get_interfaces(), key=lambda interface: interface.name.lower()), ++ "structs": sorted(namespace.get_effective_records(), key=lambda record: record.name.lower()), ++ "unions": sorted(namespace.get_unions(), key=lambda union: union.name.lower()), ++ } ++ ++ all_indices = { ++ "aliases": _check_aliases, ++ "bitfields": _check_bitfields, ++ "callbacks": _check_callbacks, ++ "classes": _check_classes, ++ "constants": _check_constants, ++ "domains": _check_domains, ++ "enums": _check_enums, ++ "functions": _check_functions, ++ "function_macros": _check_function_macros, ++ "interfaces": _check_interfaces, ++ "structs": _check_records, ++ "unions": _check_unions, ++ } ++ ++ results = [] ++ ++ # Each section is isolated, so we run it into a thread pool ++ for section in all_indices: ++ checker = all_indices.get(section, None) ++ if checker is None: ++ log.error(f"No checker for section {section}") ++ continue ++ ++ s = symbols.get(section, None) ++ if s is None: ++ log.debug(f"No symbols for section {section}") ++ continue ++ ++ log.debug(f"Checking symbols for section {section}") ++ checker(config, repository, s, results) ++ ++ for res in results: ++ log.warning(res) ++ ++ if len(results) == 0: ++ return 0 ++ else: ++ return 1 ++ ++ ++def add_args(parser): ++ parser.add_argument("-C", "--config", metavar="FILE", help="the configuration file") ++ parser.add_argument("--add-include-path", action="append", dest="include_paths", default=[], ++ help="include paths for other GIR files") ++ parser.add_argument("infile", metavar="GIRFILE", type=argparse.FileType('r', encoding='UTF-8'), ++ default=sys.stdin, help="the GIR file to parse") ++ ++ ++def run(options): ++ log.info(f"Loading config file: {options.config}") ++ ++ conf = config.GIDocConfig(options.config) ++ ++ paths = [] ++ paths.extend(options.include_paths) ++ paths.extend(utils.default_search_paths()) ++ log.info(f"Search paths: {paths}") ++ ++ parser = gir.GirParser(search_paths=paths) ++ parser.parse(options.infile) ++ ++ log.checkpoint() ++ return check(parser.get_repository(), conf) diff --cc subprojects/gi-docgen/gidocgen/gdgendeps.py index 89cac7f7b0,0000000000..c6186a17a4 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/gdgendeps.py +++ b/subprojects/gi-docgen/gidocgen/gdgendeps.py @@@ -1,88 -1,0 +1,91 @@@ +# SPDX-FileCopyrightText: 2021 GNOME Foundation +# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +import argparse +import os +import sys + +from . import config, gir, log, utils + + +HELP_MSG = "Generates the build dependencies" + + - def _gen_content_files(config, content_dir): ++def _gen_content_files(config, content_dirs): + content_files = [] + for file_name in config.content_files: - content_files.append(os.path.join(content_dir, file_name)) ++ content_files.append(utils.find_extra_content_file(content_dirs, file_name)) + return content_files + + - def _gen_content_images(config, content_dir): ++def _gen_content_images(config, content_dirs): + content_images = [] + for image_file in config.content_images: - content_images.append(os.path.join(content_dir, image_file)) ++ content_images.append(utils.find_extra_content_file(content_dirs, image_file)) + return content_images + + +def gen_dependencies(repository, config, options): + outfile = options.outfile + + outfile.write(options.config) + outfile.write("\n") + + for name in repository.includes: + include = repository.includes[name] + if include.girfile is not None: + outfile.write(include.girfile) + outfile.write("\n") + + outfile.write(repository.girfile) + outfile.write("\n") + - content_dir = options.content_dir or os.getcwd() ++ content_dirs = options.content_dirs ++ if content_dirs == []: ++ content_dirs = [os.getcwd()] + - content_files = _gen_content_files(config, content_dir) ++ content_files = _gen_content_files(config, content_dirs) + for f in content_files: + outfile.write(f) + outfile.write("\n") + - content_images = _gen_content_images(config, content_dir) ++ content_images = _gen_content_images(config, content_dirs) + for f in content_images: + outfile.write(f) + outfile.write("\n") + + +def add_args(parser): + parser.add_argument("--add-include-path", action="append", dest="include_paths", default=[], + help="include paths for other GIR files") + parser.add_argument("-C", "--config", metavar="FILE", help="the configuration file") - parser.add_argument("--content-dir", default=None, help="the base directory with the extra content") ++ parser.add_argument("--content-dir", action="append", dest="content_dirs", default=[], ++ help="the base directories with the extra content") + parser.add_argument("--dry-run", action="store_true", help="parses the GIR file without generating files") + parser.add_argument("infile", metavar="GIRFILE", type=argparse.FileType('r', encoding='UTF-8'), + default=sys.stdin, help="the GIR file to parse") + parser.add_argument("outfile", metavar="DEPFILE", type=argparse.FileType('w', encoding='UTF-8'), + default=sys.stdout, help="the dependencies file to generate") + + +def run(options): + # If we're sending output to stdout, we disable logging + if options.outfile.name == "": + log.set_quiet(True) + + log.info(f"Loading config file: {options.config}") + conf = config.GIDocConfig(options.config) + + paths = [] + paths.extend(options.include_paths) + paths.extend(utils.default_search_paths()) + log.info(f"Search paths: {paths}") + + log.info("Parsing GIR file") + parser = gir.GirParser(search_paths=paths) + parser.parse(options.infile) + + if not options.dry_run: + gen_dependencies(parser.get_repository(), conf, options) + + return 0 diff --cc subprojects/gi-docgen/gidocgen/gdgenerate.py index 8b78259ad1,0000000000..325c11ad6a mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/gdgenerate.py +++ b/subprojects/gi-docgen/gidocgen/gdgenerate.py @@@ -1,2749 -1,0 +1,3034 @@@ +# SPDX-FileCopyrightText: 2021 GNOME Foundation +# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +import argparse +import concurrent.futures +import jinja2 +import markdown +import os +import shutil +import sys + +import xml.etree.ElementTree as etree + +from markupsafe import Markup + +from . import config, gir, log, utils +from . import gdgenindices + + +HELP_MSG = "Generates the reference" + +MISSING_DESCRIPTION = "No description available." + +STRING_TYPES = { - 'utf8': 'The string is a NUL terminated UTF-8 string.', - 'filename': 'The string is a file system path, using the OS encoding.', ++ 'utf8': 'The value is a NUL terminated UTF-8 string.', ++ 'filename': 'The value is a file system path, using the OS encoding.', ++} ++ ++STRING_ELEMENT_TYPES = { ++ 'utf8': 'Each element is a NUL terminated UTF-8 string.', ++ 'filename': 'Each element is a file system path, using the OS encoding.', +} + +ARG_TRANSFER_MODES = { + 'none': 'The data is owned by the caller of the function.', + 'container': 'The called function takes ownership of the data container, but not the data inside it.', + 'full': 'The called function takes ownership of the data, and is responsible for freeing it.', +} + +METHOD_ARG_TRANSFER_MODES = { + 'none': 'The data is owned by the caller of the function.', + 'container': 'The instance takes ownership of the data container, but not the data inside it.', + 'full': 'The instance takes ownership of the data, and is responsible for freeing it.', +} + +RETVAL_TRANSFER_MODES = { + 'none': 'The data is owned by the called function.', + 'container': 'The caller of the function takes ownership of the data container, but not the data inside it.', + 'full': 'The caller of the function takes ownership of the data, and is responsible for freeing it.', + 'floating': 'The returned data has a floating reference.', +} + +METHOD_RETVAL_TRANSFER_MODES = { + 'none': 'The data is owned by the instance.', - 'container': 'The caller of the function takes ownership of the data container, but not the data inside it.', - 'full': 'The caller of the function takes ownership of the data, and is responsible for freeing it.', ++ 'container': 'The caller of the method takes ownership of the data container, but not the data inside it.', ++ 'full': 'The caller of the method takes ownership of the data, and is responsible for freeing it.', + 'floating': 'The returned data has a floating reference.', +} + +DIRECTION_MODES = { + 'in': '-', + 'inout': 'The argument will be modified by the function.', + 'out': 'The argument will be set by the function.', +} + +SCOPE_MODES = { + 'none': '-', - 'call': 'Arguments are valid during the call.', - 'notified': 'Arguments are valid until the notify function is called.', - 'async': 'Arguments are valid until the call is completed.', ++ 'call': 'The callback arguments are valid during the call.', ++ 'notified': 'The callback arguments are valid until the notify function is called.', ++ 'async': 'The callback arguments are valid until the asynchronous call is completed.', +} + +SIGNAL_WHEN = { + 'first': "The default handler is called before the handlers added via `g_signal_connect()`.", + 'last': "The default handler is called after the handlers added via `g_signal_connect()`.", + 'cleanup': "The default handler is called after the handlers added via `g_signal_connect_after()`.", +} + +FRAGMENT = { + "aliases": "alias", + "bitfields": "flags", + "callbacks": "callback", + "classes": "class", + "constants": "const", + "domains": "error", + "enums": "enum", + "functions": "func", + "function_macros": "func", + "interfaces": "iface", + "structs": "struct", + "unions": "union", +} + + +def type_name_to_cname(fqtn, is_pointer=False): + res = [] + try: + ns, name = fqtn.split('.', 1) + res.append(ns) + res.append(name) + except ValueError: + res.append(fqtn.replace('.', '')) + if is_pointer: + res.append('*') + return "".join(res) + + +def gen_index_func(func, namespace, md=None): + """Generates a dictionary with the callable metadata required by an index template""" + name = func.name + if getattr(func, "identifier"): + identifier = func.identifier + else: + identifier = None + if func.doc is not None: + summary = utils.preprocess_docs(func.doc.content, namespace, summary=True, md=md) + else: + summary = MISSING_DESCRIPTION + if func.available_since is not None: + available_since = func.available_since + else: + available_since = None + if func.deprecated_since is not None: + (version, msg) = func.deprecated_since + deprecated_since = version + else: + deprecated_since = None + return { + "name": name, + "identifier": identifier, + "summary": summary, + "available_since": available_since, + "deprecated_since": deprecated_since, + } + + +def gen_index_property(prop, namespace, md=None): + name = prop.name + if prop.doc is not None: + summary = utils.preprocess_docs(prop.doc.content, namespace, summary=True, md=md) + else: + summary = MISSING_DESCRIPTION + if prop.available_since is not None: + available_since = prop.available_since + else: + available_since = None + if prop.deprecated_since is not None: + (version, msg) = prop.deprecated_since + deprecated_since = version + else: + deprecated_since = None + return { + "name": name, + "summary": summary, + "available_since": available_since, + "deprecated_since": deprecated_since, + } + + +def gen_index_signal(signal, namespace, md=None): + name = signal.name + if signal.doc is not None: + summary = utils.preprocess_docs(signal.doc.content, namespace, summary=True, md=md) + else: + summary = MISSING_DESCRIPTION + if signal.available_since is not None: + available_since = signal.available_since + else: + available_since = None + if signal.deprecated_since is not None: + (version, msg) = signal.deprecated_since + deprecated_since = version + else: + deprecated_since = None + return { + "name": name, + "summary": summary, + "available_since": available_since, + "deprecated_since": deprecated_since, + } + + - def gen_type_link(namespace, name): - t = namespace.find_real_type(name) - if t is not None: - if isinstance(t, gir.Alias): - return f"{t.ctype}" - elif isinstance(t, gir.BitField): - return f"{t.ctype}" - elif isinstance(t, gir.Class): - return f"{t.ctype}" - elif isinstance(t, gir.ErrorDomain): - return f"{t.ctype}" - elif isinstance(t, gir.Enumeration): - return f"{t.ctype}" - elif isinstance(t, gir.Interface): - return f"{t.ctype}" - elif isinstance(t, gir.Record): - return f"{t.ctype}" - elif isinstance(t, gir.Union): - return f"{t.ctype}" - return f"{namespace.identifier_prefix[0]}{name}" ++def gen_index_ancestor(ancestor_type, namespace, config, md=None): ++ ancestor_name = ancestor_type.name ++ if '.' in ancestor_name: ++ ns, ancestor_name = ancestor_name.split('.') ++ else: ++ ns = ancestor_type.namespace or namespace.name ++ res = namespace.repository.find_class(ancestor_name, ns) ++ if res is not None: ++ ancestor_ns = res[0].name ++ ancestor_ctype = res[1].base_ctype ++ ancestor = res[1] ++ else: ++ ancestor_ns = ancestor_type.namespace or namespace.name ++ ancestor_ctype = ancestor_type.base_ctype ++ ancestor = None ++ n_methods = 0 ++ methods = [] ++ n_properties = 0 ++ properties = [] ++ n_signals = 0 ++ signals = [] ++ # We don't use real Template objects, here, because it can be ++ # extremely expensive, unless we add a cache somewhere ++ if ancestor is not None: ++ # Set a hard-limit on the number of methods; base types can ++ # add *a lot* of them; two dozens feel like a good compromise ++ for m in ancestor.methods: ++ is_hidden = config.is_hidden(ancestor_name, "method", m.name) ++ if not is_hidden: ++ n_methods += 1 ++ if n_methods > 0 and n_methods < 24: ++ for m in ancestor.methods: ++ if not config.is_hidden(ancestor_name, "method", m.name): ++ methods.append(gen_index_func(m, namespace, md)) ++ for p in ancestor.properties.values(): ++ if not config.is_hidden(ancestor_name, "property", p.name): ++ n_properties += 1 ++ properties.append(gen_index_property(p, namespace, md)) ++ for s in ancestor.signals.values(): ++ if not config.is_hidden(ancestor_name, "signal", s.name): ++ n_signals += 1 ++ signals.append(gen_index_signal(s, namespace, md)) ++ return { ++ "namespace": ancestor_ns, ++ "name": ancestor_name, ++ "fqtn": f"{ancestor_ns}.{ancestor_name}", ++ "type_cname": ancestor_ctype, ++ "properties": properties, ++ "n_properties": n_properties, ++ "signals": signals, ++ "n_signals": n_signals, ++ "methods": methods, ++ "n_methods": n_methods, ++ } ++ ++ ++def gen_index_implements(iface_type, namespace, config, md=None): ++ iface_name = iface_type.name ++ if '.' in iface_name: ++ ns, iface_name = iface_name.split('.') ++ else: ++ ns = iface_type.namespace or namespace.name ++ res = namespace.repository.find_interface(iface_name, ns) ++ if res is not None: ++ iface_ns = res[0].name ++ iface_ctype = res[1].base_ctype ++ iface = res[1] ++ else: ++ iface_ns = iface_type.namespace or namespace.name ++ iface_ctype = iface_type.base_ctype ++ iface = None ++ n_methods = 0 ++ methods = [] ++ n_properties = 0 ++ properties = [] ++ n_signals = 0 ++ signals = [] ++ if iface is not None: ++ # Set a hard-limit on the number of methods; base types can ++ # add *a lot* of them; two dozens feel like a good compromise ++ for m in iface.methods: ++ is_hidden = config.is_hidden(iface_name, "method", m.name) ++ if not is_hidden: ++ n_methods += 1 ++ if n_methods > 0 and n_methods < 24: ++ for m in iface.methods: ++ if not config.is_hidden(iface_name, "method", m.name): ++ methods.append(gen_index_func(m, namespace, md)) ++ for p in iface.properties.values(): ++ if not config.is_hidden(iface_name, "property", p.name): ++ n_properties += 1 ++ properties.append(gen_index_property(p, namespace, md)) ++ for s in iface.signals.values(): ++ if not config.is_hidden(iface.name, "signal", s.name): ++ n_signals += 1 ++ signals.append(gen_index_signal(s, namespace, md)) ++ return { ++ "namespace": iface_ns, ++ "name": iface_name, ++ "fqtn": f"{iface_ns}.{iface_name}", ++ "type_cname": iface_ctype, ++ "properties": properties, ++ "n_properties": n_properties, ++ "signals": signals, ++ "n_signals": n_signals, ++ "methods": methods, ++ "n_methods": n_methods, ++ } ++ ++ ++def gen_type_link(repository, namespace, name, ctype=None): ++ res = repository.find_type(name, ns=namespace) ++ if res is None: ++ if ctype is not None: ++ return f"{ctype}" ++ elif name in ['utf8', 'filename']: ++ return "char*" ++ else: ++ return f"{name}" ++ ++ ns, t = res ++ if t.is_fundamental: ++ return f"{t.ctype}" ++ ++ if isinstance(t, gir.Alias): ++ link = f"alias.{name}.html" ++ elif isinstance(t, gir.BitField): ++ link = f"flags.{name}.html" ++ elif isinstance(t, gir.Callback): ++ link = f"callback.{name}.html" ++ elif isinstance(t, gir.Class): ++ link = f"class.{name}.html" ++ elif isinstance(t, gir.ErrorDomain): ++ link = f"error.{name}.html" ++ elif isinstance(t, gir.Enumeration): ++ link = f"enum.{name}.html" ++ elif isinstance(t, gir.Interface): ++ link = f"iface.{name}.html" ++ elif isinstance(t, gir.Record): ++ link = f"struct.{name}.html" ++ elif isinstance(t, gir.Union): ++ link = f"union.{name}.html" ++ else: ++ return f"{t.ctype}" ++ ++ text = f"{t.ctype}" ++ if ns.name == repository.namespace.name: ++ href = f'href="{link}"' ++ css_class = "" ++ data_link = "" ++ data_ns = "" ++ else: ++ href = 'href="javascript:void(0)"' ++ css_class = ' class="external"' ++ data_link = f' data-link="{link}"' ++ data_ns = f' data-namespace="{ns.name}"' ++ ++ return f"{text}" + + +class TemplateConstant: + def __init__(self, namespace, const): + self.value = const.value + self.identifier = const.ctype + self.type_cname = const.target.ctype + self.namespace = namespace.name + self.name = const.name + self.fqtn = f"{namespace.name}.{const.name}" + + if const.doc is not None: + self.summary = utils.preprocess_docs(const.doc.content, namespace, summary=True) + self.description = utils.preprocess_docs(const.doc.content, namespace) + filename = const.doc.filename + if filename.startswith('../'): + filename = filename.replace('../', '') + line = const.doc.line + const.docs_location = (filename, line) + else: + self.description = MISSING_DESCRIPTION + + self.stability = const.stability + self.attributes = const.attributes + self.available_since = const.available_since + if const.deprecated_since is not None: + (version, msg) = const.deprecated_since + self.deprecated_since = { + "version": version, + "message": utils.preprocess_docs(msg, namespace), + } + else: + self.deprecated_since = None + + self.introspectable = const.introspectable + self.hierarchy_svg = None + + @property + def c_decl(self): + return utils.code_highlight(f"#define {self.identifier} {self.value}") + + +class TemplateProperty: + def __init__(self, namespace, type_, prop): + self.name = prop.name + self.type_name = prop.target.name + self.type_cname = prop.target.ctype - if self.type_cname is None: - self.type_cname = type_name_to_cname(prop.target.name, True) ++ self.is_fundamental = prop.target.is_fundamental ++ self.is_array = isinstance(prop.target, gir.ArrayType) ++ self.is_list = isinstance(prop.target, gir.ListType) ++ self.is_list_model = prop.target.name in ['Gio.ListModel', 'GListModel'] + self.readable = prop.readable + self.writable = prop.writable + self.construct = prop.construct + self.construct_only = prop.construct_only ++ if self.type_cname is None: ++ if prop.target.is_fundamental: ++ self.type_cname = prop.target.name ++ elif self.is_array or self.is_list: ++ value_type = prop.target.value_type ++ if value_type.name in ['utf8', 'filename']: ++ self.type_cname = 'gchar*' ++ elif value_type.ctype is None: ++ self.type_cname = type_name_to_cname(value_type.name, True) ++ else: ++ self.type_cname = value_type.ctype ++ else: ++ self.type_cname = type_name_to_cname(prop.target.name, True) + if prop.doc is not None: + self.summary = utils.preprocess_docs(prop.doc.content, namespace, summary=True) + self.description = utils.preprocess_docs(prop.doc.content, namespace) + filename = prop.doc.filename + if filename.startswith('../'): + filename = filename.replace('../', '') + line = prop.doc.line + self.docs_location = (filename, line) + else: + self.description = MISSING_DESCRIPTION + + self.stability = prop.stability + self.available_since = prop.available_since + if prop.deprecated_since is not None: + (version, msg) = prop.deprecated_since + self.deprecated_since = { + "version": version, + "message": utils.preprocess_docs(msg, namespace), + } + else: + self.deprecated_since = None + + self.introspectable = prop.introspectable + + def transform_set_attribute(namespace, prop, setter_func): + if setter_func is None: + log.warning(f"Missing value in the set attribute for {prop.name}") + return None + t = namespace.find_symbol(setter_func) + if t is None: + log.warning(f"Invalid Property.set attribute for {prop.name}: {setter_func}") + return setter_func + if not (isinstance(t, gir.Class) or isinstance(t, gir.Interface)): + log.warning(f"Invalid setter function {setter_func} for property {namespace.name}.{t.name}:{prop.name}") + return setter_func + func_name = setter_func.replace(namespace.symbol_prefix[0] + '_', '') + func_name = func_name.replace(t.symbol_prefix + '_', '') + href = f"method.{t.name}.{func_name}.html" + return Markup(f"{setter_func}") + + def transform_get_attribute(namespace, prop, getter_func): + if getter_func is None: + log.warning(f"Missing value in the get attribute for {prop.name}") + return None + t = namespace.find_symbol(getter_func) + if t is None: + log.warning(f"Invalid Property.get attribute for {prop.name}: {getter_func}") + return getter_func + if not (isinstance(t, gir.Class) or isinstance(t, gir.Interface)): + log.warning(f"Invalid getter function {getter_func} for property {namespace.name}.{t.name}:{prop.name}") + return getter_func + func_name = getter_func.replace(namespace.symbol_prefix[0] + '_', '') + func_name = func_name.replace(t.symbol_prefix + '_', '') + href = f"method.{t.name}.{func_name}.html" + return Markup(f"{getter_func}") + ++ def transform_default_attribute(namespace, prop, default_value): ++ if default_value is None: ++ log.warning(f"Missing value in the default attribute for {prop.name}") ++ return None ++ return Markup(f"{default_value}") ++ + ATTRIBUTE_NAMES = { + "org.gtk.Property.set": { + "label": "Setter method", + "transform": transform_set_attribute, + }, + "org.gtk.Property.get": { + "label": "Getter method", + "transform": transform_get_attribute, + }, ++ "org.gtk.Property.default": { ++ "label": "Default value", ++ "transform": transform_default_attribute, ++ }, + } + + self.attributes = {} + for name in (prop.attributes or {}): + value = prop.attributes[name] + if name in ATTRIBUTE_NAMES: + label = ATTRIBUTE_NAMES[name].get("label") + transform = ATTRIBUTE_NAMES[name].get("transform") + if transform is not None: + self.attributes[label] = transform(namespace, prop, value) + else: + self.attributes[name] = value - if self.type_name is not None: ++ ++ def gen_method_link(ns, t, method): ++ for m in t.methods: ++ if m.name == method: ++ href = f"method.{t.name}.{m.name}.html" ++ return Markup(f'{m.identifier}()') ++ return None ++ ++ if prop.setter is not None: ++ link = gen_method_link(namespace, type_, prop.setter) ++ if link is not None: ++ self.attributes["Setter method"] = link ++ if prop.getter is not None: ++ link = gen_method_link(namespace, type_, prop.getter) ++ if link is not None: ++ self.attributes["Getter method"] = link ++ ++ if self.is_array: ++ name = prop.target.value_type.name ++ elif self.is_list: ++ name = prop.target.value_type.name ++ elif self.type_name is not None: + name = self.type_name + else: + name = None + if name is not None: - if name.startswith(namespace.name): - self.link = gen_type_link(namespace, name[len(namespace.name) + 1:]) ++ if self.is_fundamental: ++ self.link = f"{self.type_cname}" ++ elif self.is_array or self.is_list: ++ self.link = f"{self.type_cname}" ++ else: ++ if '.' in name: ++ ns, name = name.split('.') ++ else: ++ ns = namespace.name ++ self.link = gen_type_link(namespace.repository, ns, name, self.type_cname) + + @property + def c_decl(self): + flags = [] + if self.readable: + flags += ['read'] + if self.writable: + flags += ['write'] + if self.construct: + flags += ['construct'] + if self.construct_only: + flags += ['construct-only'] + flags = ", ".join(flags) + return f"property {self.name}: {self.type_name} [ {flags} ]" + + +class TemplateArgument: + def __init__(self, namespace, call, argument): + self.name = argument.name + self.type_name = argument.target.name - self.type_cname = argument.target.ctype - if self.type_cname is None: - self.type_cname = type_name_to_cname(argument.target.name, True) ++ if isinstance(call, gir.FunctionMacro): ++ self.type_cname = '-' ++ else: ++ self.type_cname = argument.target.ctype ++ if self.type_cname is None: ++ self.type_cname = type_name_to_cname(argument.target.name, True) + self.is_array = isinstance(argument.target, gir.ArrayType) + self.is_list = isinstance(argument.target, gir.ListType) + self.is_map = isinstance(argument.target, gir.MapType) + self.is_varargs = isinstance(argument.target, gir.VarArgs) + self.is_macro = isinstance(call, gir.FunctionMacro) ++ self.is_list_model = self.type_name in ['Gio.ListModel', 'GListModel'] ++ self.is_fundamental = argument.target.is_fundamental + self.transfer = argument.transfer or 'none' + if isinstance(call, gir.Method): + self.transfer_note = METHOD_ARG_TRANSFER_MODES[argument.transfer or 'none'] + else: + self.transfer_note = ARG_TRANSFER_MODES[argument.transfer or 'none'] + self.direction = argument.direction or 'in' + self.direction_note = DIRECTION_MODES[argument.direction] + self.optional = argument.optional + self.nullable = argument.nullable + self.scope = SCOPE_MODES[argument.scope or 'none'] + self.introspectable = argument.introspectable - if self.type_name in ['utf8', 'filename']: - self.string_note = STRING_TYPES[self.type_name] + if argument.closure != -1: + self.closure = call.parameters[argument.closure] + else: + self.closure = None + if self.is_array: + self.value_type = argument.target.value_type.name + self.value_type_cname = argument.target.value_type.ctype + self.fixed_size = argument.target.fixed_size + self.zero_terminated = argument.target.zero_terminated + self.len_arg = argument.target.length != -1 and call.parameters[argument.target.length].name + if self.is_list: + self.value_type = argument.target.value_type.name + self.value_type_cname = argument.target.value_type.ctype ++ if self.is_list_model: ++ self.value_type = argument.attributes.get('element-type', 'GObject') ++ if self.type_name in ['utf8', 'filename']: ++ self.string_note = STRING_TYPES[self.type_name] ++ elif self.is_array or self.is_list: ++ if self.value_type in ['utf8', 'filename']: ++ self.string_note = STRING_ELEMENT_TYPES[self.value_type] + if argument.doc is not None: + self.summary = utils.preprocess_docs(argument.doc.content, namespace, summary=True) + self.description = utils.preprocess_docs(argument.doc.content, namespace) + else: + self.description = MISSING_DESCRIPTION + if self.is_array: + name = self.value_type + elif self.is_list: + name = self.value_type + elif self.type_name is not None: + name = self.type_name + else: + name = None + if name is not None: - if name.startswith(namespace.name): - self.link = gen_type_link(namespace, name[len(namespace.name) + 1:]) ++ if self.is_fundamental: ++ self.link = f"{self.type_cname}" ++ elif self.is_array: ++ self.link = f"{self.value_type_cname}" ++ elif self.is_list: ++ self.link = f"{self.value_type_cname}" ++ elif self.is_list_model: ++ self.link = f"{self.value_type}" + else: - if self.is_array: - self.link = f"{self.value_type_cname}" - elif self.is_list: - self.link = f"{self.value_type_cname}" ++ if '.' in name: ++ ns, name = name.split('.') ++ else: ++ ns = namespace.name ++ self.link = gen_type_link(namespace.repository, ns, name, self.type_cname) + + @property + def is_pointer(self): + return '*' in self.type_cname + + @property + def c_decl(self): + if self.is_varargs: + return "..." + elif self.is_macro: + return f"{self.name}" + else: + return f"{self.type_cname} {self.name}" + + +class TemplateReturnValue: + def __init__(self, namespace, call, retval): + self.name = retval.name + self.type_name = retval.target.name + self.type_cname = retval.target.ctype ++ self.is_fundamental = retval.target.is_fundamental + if self.type_cname is None: + self.type_cname = type_name_to_cname(retval.target.name, True) + self.is_array = isinstance(retval.target, gir.ArrayType) + self.is_list = isinstance(retval.target, gir.ListType) ++ self.is_list_model = self.type_name in ['Gio.ListModel', 'GListModel'] + self.transfer = retval.transfer or 'none' + if isinstance(call, gir.Method): + self.transfer_note = METHOD_RETVAL_TRANSFER_MODES[retval.transfer or 'none'] + else: + self.transfer_note = RETVAL_TRANSFER_MODES[retval.transfer or 'none'] + self.nullable = retval.nullable + if self.is_array: + self.value_type = retval.target.value_type.name + self.value_type_cname = retval.target.value_type.ctype + self.fixed_size = retval.target.fixed_size + self.zero_terminated = retval.target.zero_terminated + self.len_arg = retval.target.length != -1 and call.parameters[retval.target.length].name + if self.is_list: + self.value_type = retval.target.value_type.name + self.value_type_cname = retval.target.value_type.ctype ++ if self.is_list_model: ++ self.value_type = retval.attributes.get('element-type', 'GObject') + if self.type_name in ['utf8', 'filename']: + self.string_note = STRING_TYPES[self.type_name] ++ elif self.is_array or self.is_list: ++ if self.value_type in ['utf8', 'filename']: ++ self.string_note = STRING_ELEMENT_TYPES[self.value_type] + if retval.doc is not None: + self.summary = utils.preprocess_docs(retval.doc.content, namespace, summary=True) + self.description = utils.preprocess_docs(retval.doc.content, namespace) + else: + self.description = MISSING_DESCRIPTION + self.introspectable = retval.introspectable + if self.is_array: + name = self.value_type + elif self.is_list: + name = self.value_type ++ elif self.is_list_model: ++ name = self.value_type + elif self.type_name is not None: + name = self.type_name + else: + name = None + if name is not None: - if name.startswith(namespace.name): - self.link = gen_type_link(namespace, name[len(namespace.name) + 1:]) ++ if self.is_fundamental: ++ self.link = f"{self.type_cname}" ++ elif self.is_array: ++ self.link = f"{self.value_type_cname}" ++ elif self.is_list: ++ self.link = f"{self.value_type_cname}" ++ elif self.is_list_model: ++ self.link = f"{self.value_type}" + else: - if self.is_array: - self.link = f"{self.value_type_cname}" - elif self.is_list: - self.link = f"{self.value_type_cname}" ++ if '.' in name: ++ ns, name = name.split('.') ++ else: ++ ns = namespace.name ++ self.link = gen_type_link(namespace.repository, ns, name, self.type_cname) + + @property + def is_pointer(self): + return '*' in self.type_cname + + +class TemplateSignal: + def __init__(self, namespace, type_, signal): + self.name = signal.name + self.type_cname = type_.base_ctype + self.identifier = signal.name.replace("-", "_") + + if signal.doc is not None: + self.summary = utils.preprocess_docs(signal.doc.content, namespace, summary=True) + self.description = utils.preprocess_docs(signal.doc.content, namespace) + filename = signal.doc.filename + if filename.startswith('../'): + filename = filename.replace('../', '') + line = signal.doc.line + self.docs_location = (filename, line) + else: + self.description = MISSING_DESCRIPTION + + self.is_detailed = signal.detailed + self.is_action = signal.action + self.no_recurse = signal.no_recurse + self.no_hooks = signal.no_hooks + if signal.when: + self.when = utils.preprocess_docs(SIGNAL_WHEN[signal.when], namespace) + + self.arguments = [] + for arg in signal.parameters: + self.arguments.append(TemplateArgument(namespace, signal, arg)) + + self.return_value = None + if not isinstance(signal.return_value.target, gir.VoidType): + self.return_value = TemplateReturnValue(namespace, signal, signal.return_value) + + self.stability = signal.stability + self.attributes = signal.attributes + self.available_since = signal.available_since + if signal.deprecated_since is not None: + (version, msg) = signal.deprecated_since + self.deprecated_since = { + "version": version, + "message": utils.preprocess_docs(msg, namespace), + } + else: + self.deprecated_since = None + + self.introspectable = signal.introspectable + + @property + def c_decl(self): + res = [] + if self.return_value is None: + res += ["void"] + else: + res += [f"{self.return_value.type_cname}"] + res += [f"{self.identifier} ("] - res += [f" {self.type_cname} self,"] ++ res += [f" {self.type_cname}* self,"] + for arg in self.arguments: + res += [f" {arg.c_decl},"] + res += [" gpointer user_data"] + res += [")"] + return utils.code_highlight("\n".join(res)) + + +class TemplateMethod: + def __init__(self, namespace, type_, method): + self.name = method.name + self.identifier = method.identifier + + if method.doc is not None: + self.summary = utils.preprocess_docs(method.doc.content, namespace, summary=True) + self.description = utils.preprocess_docs(method.doc.content, namespace) + filename = method.doc.filename + line = method.doc.line + if filename.startswith('../'): + filename = filename.replace('../', '') + self.docs_location = (filename, line) + else: + self.description = MISSING_DESCRIPTION + + self.throws = method.throws + + self.instance_parameter = TemplateArgument(namespace, method, method.instance_param) + + self.arguments = [] + for arg in method.parameters: + self.arguments.append(TemplateArgument(namespace, method, arg)) + + self.return_value = None + if not isinstance(method.return_value.target, gir.VoidType): + self.return_value = TemplateReturnValue(namespace, method, method.return_value) + + self.stability = method.stability + self.available_since = method.available_since + if method.deprecated_since is not None: + (version, msg) = method.deprecated_since + self.deprecated_since = { + "version": version, + "message": utils.preprocess_docs(msg, namespace), + } + else: + self.deprecated_since = None + + if method.source_position is not None: + filename, line = method.source_position + if filename.startswith('../'): + filename = filename.replace('../', '') + self.source_location = (filename, line) + + self.introspectable = method.introspectable + + def transform_property_attribute(namespace, type_, method, value): + if value in type_.properties: + text = f"{namespace.name}.{type_.name}:{value}" + href = f"property.{type_.name}.{value}.html" + return Markup(f"{text}") + log.warning(f"Property {value} linked to method {method.name} not found in {namespace.name}.{type_.name}") + return value + + def transform_signal_attribute(namespace, type_, method, value): + if value in type_.signals: + text = f"{namespace.name}.{type_.name}::{value}" + href = f"signal.{type_.name}.{value}.html" + return Markup(f"{text}") + log.warning(f"Signal {value} linked to method {method.name} not found in {namespace.name}.{type_.name}") + return value + + ATTRIBUTE_NAMES = { + "org.gtk.Method.set_property": { + "label": "Sets property", + "transform": transform_property_attribute, + }, + "org.gtk.Method.get_property": { + "label": "Gets property", + "transform": transform_property_attribute, + }, + "org.gtk.Method.signal": { + "label": "Emits signal", + "transform": transform_signal_attribute, + } + } + + self.attributes = {} + for name in (method.attributes or {}): + value = method.attributes[name] + if name in ATTRIBUTE_NAMES: + label = ATTRIBUTE_NAMES[name].get("label") + transform = ATTRIBUTE_NAMES[name].get("transform") + if transform is not None: + self.attributes[label] = transform(namespace, type_, method, value) + else: + self.attributes[name] = value + ++ def gen_property_link(namespace, t, prop_name): ++ if prop_name not in t.properties: ++ return None ++ prop = t.properties[prop_name] ++ text = f"{namespace.name}.{t.name}:{prop.name}" ++ href = f"property.{t.name}.{prop.name}.html" ++ return Markup(f'{text}') ++ ++ if isinstance(method, gir.Method): ++ if method.set_property is not None: ++ link = gen_property_link(namespace, type_, method.set_property) ++ if link is not None: ++ self.attributes["Sets property"] = link ++ if method.get_property is not None: ++ link = gen_property_link(namespace, type_, method.get_property) ++ if link is not None: ++ self.attributes["Gets property"] = link ++ + @property + def c_decl(self): + res = [] + if self.return_value is None: + res += ["void"] + else: + res += [f"{self.return_value.type_cname}"] + if self.identifier is not None: + res += [f"{self.identifier} ("] + else: + res += [f"{self.name} ("] + n_args = len(self.arguments) + if n_args == 0: + res += [f" {self.instance_parameter.type_cname} {self.instance_parameter.name}"] + else: + res += [f" {self.instance_parameter.type_cname} {self.instance_parameter.name},"] + for (idx, arg) in enumerate(self.arguments): + if idx == n_args - 1 and not self.throws: + res += [f" {arg.c_decl}"] + else: + res += [f" {arg.c_decl},"] + if self.throws: + res += [" GError** error"] + res += [")"] + return utils.code_highlight("\n".join(res)) + + +class TemplateClassMethod: + def __init__(self, namespace, cls, method): + self.name = method.name + self.identifier = method.identifier - self.class_type_cname = cls.type_struct ++ self.class_type_cname = namespace.identifier_prefix[0] + cls.type_struct + + self.throws = method.throws + + if method.doc is not None: + self.summary = utils.preprocess_docs(method.doc.content, namespace, summary=True) + self.description = utils.preprocess_docs(method.doc.content, namespace) + filename = method.doc.filename + line = method.doc.line + if filename.startswith('../'): + filename = filename.replace('../', '') + self.docs_location = (filename, line) + else: + self.description = MISSING_DESCRIPTION + ++ self.instance_parameter = TemplateArgument(namespace, method, method.instance_param) ++ + self.arguments = [] + for arg in method.parameters: + self.arguments.append(TemplateArgument(namespace, method, arg)) + + self.return_value = None + if not isinstance(method.return_value.target, gir.VoidType): + self.return_value = TemplateReturnValue(namespace, method, method.return_value) + + self.stability = method.stability + self.attributes = method.attributes + self.available_since = method.available_since + if method.deprecated_since is not None: + (version, msg) = method.deprecated_since + self.deprecated_since = { + "version": version, + "message": utils.preprocess_docs(msg, namespace), + } + else: + self.deprecated_since = None + + if method.source_position is not None: + filename, line = method.source_position + if filename.startswith('../'): + filename = filename.replace('../', '') + self.source_location = (filename, line) + + self.introspectable = method.introspectable + + @property + def c_decl(self): + res = [] + if self.return_value is None: + res += ["void"] + else: + res += [f"{self.return_value.type_cname}"] + res += [f"{self.identifier} ("] + n_args = len(self.arguments) - if n_args == 1: - res += [f" {self.class_type_cname}* self"] ++ if n_args == 0: ++ res += [f" {self.instance_parameter.type_cname} {self.instance_parameter.name}"] + else: - res += [f" {self.class_type_cname}* self,"] - for (idx, arg) in enumerate(self.arguments, start=1): ++ res += [f" {self.instance_parameter.type_cname} {self.instance_parameter.name},"] ++ for (idx, arg) in enumerate(self.arguments): + if idx == n_args - 1 and not self.throws: + res += [f" {arg.c_decl}"] + else: + res += [f" {arg.c_decl},"] + if self.throws: + res += [" GError** error"] + res += [")"] + return utils.code_highlight("\n".join(res)) + + +class TemplateFunction: + def __init__(self, namespace, func): + self.identifier = func.identifier + self.name = func.name + self.namespace = namespace.name + + self.is_macro = isinstance(func, gir.FunctionMacro) + + self.throws = func.throws + + if func.doc is not None: + self.summary = utils.preprocess_docs(func.doc.content, namespace, summary=True) + self.description = utils.preprocess_docs(func.doc.content, namespace) + filename = func.doc.filename + line = func.doc.line + if filename.startswith('../'): + filename = filename.replace('../', '') + self.docs_location = (filename, line) + else: + self.description = MISSING_DESCRIPTION + + self.arguments = [] + for arg in func.parameters: + self.arguments.append(TemplateArgument(namespace, func, arg)) + + self.return_value = None + if not isinstance(func.return_value.target, gir.VoidType): + self.return_value = TemplateReturnValue(namespace, func, func.return_value) + + self.stability = func.stability + self.attributes = func.attributes + self.available_since = func.available_since + if func.deprecated_since is not None: + (version, msg) = func.deprecated_since + self.deprecated_since = { + "version": version, + "message": utils.preprocess_docs(msg, namespace), + } + else: + self.deprecated_since = None + + if func.source_position is not None: + filename, line = func.source_position + if filename.startswith('../'): + filename = filename.replace('../', '') + self.source_location = (filename, line) + + self.introspectable = func.introspectable + + @property + def c_decl(self): + res = [] + if self.is_macro: + res += [f"#define {self.identifier} ("] + else: + if self.return_value is None: + res += ["void"] + else: + res += [f"{self.return_value.type_cname}"] + res += [f"{self.identifier} ("] + n_args = len(self.arguments) + if n_args == 0: + res += [" void"] + else: + for (idx, arg) in enumerate(self.arguments): + if idx == n_args - 1 and not self.throws: + res += [f" {arg.c_decl}"] + else: + res += [f" {arg.c_decl},"] + if self.throws: + res += [" GError** error"] + res += [")"] + return utils.code_highlight("\n".join(res)) + + +class TemplateCallback: + def __init__(self, namespace, cb, field=False): + self.name = cb.name ++ self.type_cname = cb.ctype + self.identifier = cb.name.replace("-", "_") + self.field = field + + if cb.doc is not None: + self.summary = utils.preprocess_docs(cb.doc.content, namespace, summary=True) + self.description = utils.preprocess_docs(cb.doc.content, namespace) + filename = cb.doc.filename + line = cb.doc.line + if filename.startswith('../'): + filename = filename.replace('../', '') + self.docs_location = (filename, line) + else: + self.description = MISSING_DESCRIPTION + + self.arguments = [] + for arg in cb.parameters: + self.arguments.append(TemplateArgument(namespace, cb, arg)) + + self.return_value = None + if not isinstance(cb.return_value.target, gir.VoidType): + self.return_value = TemplateReturnValue(namespace, cb, cb.return_value) + + self.throws = cb.throws + + self.stability = cb.stability + self.attributes = cb.attributes + self.available_since = cb.available_since + if cb.deprecated_since is not None: + (version, msg) = cb.deprecated_since + self.deprecated_since = { + "version": version, + "message": utils.preprocess_docs(msg, namespace), + } + else: + self.deprecated_since = None + + self.introspectable = cb.introspectable + + @property + def c_decl(self): + res = [] + if self.field: + arg_indent = " " + else: + arg_indent = " " + if self.return_value is None: + retval = "void" + else: + retval = f"{self.return_value.type_cname}" + if self.field: + res += [f"{retval} (* {self.identifier}) ("] + else: + res += [retval] - res += [f"{self.identifier} ("] ++ res += [f"(* {self.type_cname}) ("] + n_args = len(self.arguments) + if n_args == 0: + res += ["void"] + else: + for (idx, arg) in enumerate(self.arguments): + if idx == n_args - 1 and not self.throws: + res += [f"{arg_indent}{arg.type_cname} {arg.name}"] + else: + res += [f"{arg_indent}{arg.type_cname} {arg.name},"] + if self.throws: + res += [f"{arg_indent}GError** error"] + if self.field: + res += [" )"] + else: + res += [")"] + if self.field: + return "\n".join(res) + else: + return utils.code_highlight("\n".join(res)) + + +class TemplateField: + def __init__(self, namespace, field): + self.name = field.name + if field.target is not None: + if isinstance(field.target, gir.Callback): + self.is_callback = True + self.type_name: field.target.name + self.type_cname = TemplateCallback(namespace, field.target, field=True).c_decl + else: + self.is_callback = False + self.type_name = field.target.name + self.type_cname = field.target.ctype + else: + self.is_callback = False + self.type_name = 'none' + self.type_cname = 'gpointer' + self.private = field.private + if field.doc is not None: + self.description = utils.preprocess_docs(field.doc.content, namespace) + else: + self.description = MISSING_DESCRIPTION + self.introspectable = field.introspectable + + +class TemplateInterface: - def __init__(self, namespace, interface): ++ def __init__(self, namespace, interface, config): + if isinstance(interface, gir.Interface): + if '.' in interface.name: + self.namespace, self.name = interface.name.split('.') + self.fqtn = interface.name + else: + self.namespace = interface.namespace + self.name = interface.name + self.fqtn = f"{self.namespace}.{self.name}" + elif isinstance(interface, gir.Type): + if '.' in interface.name: + self.namespace, self.name = interface.name.split('.') + else: + self.namespace = interface.namespace or namespace.name + self.name = interface.name + self.fqtn = f"{self.namespace}.{self.name}" + self.requires = "GObject.Object" + self.link_prefix = "iface" + self.description = MISSING_DESCRIPTION + return + + md = markdown.Markdown(extensions=utils.MD_EXTENSIONS, + extension_configs=utils.MD_EXTENSIONS_CONF) + + requires = interface.prerequisite + if requires is None: + self.requires_namespace = "GObject" + self.requires_name = "Object" ++ self.requires_ctype = "GObject" + elif '.' in requires.name: + self.requires_namespace, self.requires_name = requires.name.split('.') ++ self.requires_ctype = requires.ctype + else: + self.requires_namespace = requires.namespace or namespace.name + self.requires_name = requires.name ++ self.requires_ctype = requires.ctype + + self.requires_fqtn = f"{self.requires_namespace}.{self.requires_name}" ++ log.debug(f"Preqrequisite for {self.fqtn}: {self.requires_fqtn}") + + self.symbol_prefix = f"{namespace.symbol_prefix[0]}_{interface.symbol_prefix}" + self.type_cname = interface.base_ctype + + self.link_prefix = "iface" + + if interface.doc is not None: + self.summary = utils.preprocess_docs(interface.doc.content, namespace, summary=True, md=md) + self.description = utils.preprocess_docs(interface.doc.content, namespace, md=md) + filename = interface.doc.filename + line = interface.doc.line + if filename.startswith('../'): + filename = filename.replace('../', '') + self.docs_location = (filename, line) + else: + self.description = MISSING_DESCRIPTION + + self.stability = interface.stability + self.attributes = interface.attributes + self.available_since = interface.available_since + if interface.deprecated_since is not None: + (version, msg) = interface.deprecated_since + self.deprecated_since = { + "version": version, + "message": utils.preprocess_docs(msg, namespace), + } + else: + self.deprecated_since = None + + self.introspectable = interface.introspectable + + self.class_name = interface.type_struct + + self.class_struct = namespace.find_record(interface.type_struct) + if self.class_struct is not None: + self.class_fields = [] + self.class_methods = [] + + for field in self.class_struct.fields: + if not field.private: + self.class_fields.append(TemplateField(namespace, field)) + + for method in self.class_struct.methods: + self.class_methods.append(gen_index_func(method, namespace, md)) + + if len(interface.properties) != 0: + self.properties = [] + for pname, prop in interface.properties.items(): - self.properties.append(gen_index_property(prop, namespace, md)) ++ if not config.is_hidden(interface.name, "property", pname): ++ self.properties.append(gen_index_property(prop, namespace, md)) + + if len(interface.signals) != 0: + self.signals = [] + for sname, signal in interface.signals.items(): - self.signals.append(gen_index_signal(signal, namespace, md)) ++ if not config.is_hidden(interface.name, "signal", sname): ++ self.signals.append(gen_index_signal(signal, namespace, md)) + + if len(interface.methods) != 0: + self.methods = [] + for method in interface.methods: - self.methods.append(gen_index_func(method, namespace, md)) ++ if not config.is_hidden(interface.name, "method", method.name): ++ self.methods.append(gen_index_func(method, namespace, md)) + + if len(interface.virtual_methods) != 0: + self.virtual_methods = [] + for vfunc in interface.virtual_methods: + self.virtual_methods.append(gen_index_func(vfunc, namespace, md)) + + if len(interface.functions) != 0: + self.type_funcs = [] + for func in interface.functions: - self.type_funcs.append(gen_index_func(func, namespace, md)) ++ if not config.is_hidden(interface.name, "function", func.name): ++ self.type_funcs.append(gen_index_func(func, namespace, md)) ++ ++ if len(interface.implementations) != 0: ++ self.implementations = [] ++ for impl in interface.implementations: ++ self.implementations.append({ ++ 'name': impl.name, ++ 'ctype': impl.ctype, ++ }) + + @property + def c_decl(self): + return f"interface {self.fqtn} : {self.requires_fqtn}" + + +class TemplateClass: - def __init__(self, namespace, cls, recurse=True): ++ def __init__(self, namespace, cls, config, recurse=True): + self.symbol_prefix = f"{namespace.symbol_prefix[0]}_{cls.symbol_prefix}" + self.type_cname = cls.base_ctype + self.link_prefix = "class" + self.fundamental = cls.fundamental + self.abstract = cls.abstract + + md = markdown.Markdown(extensions=utils.MD_EXTENSIONS, + extension_configs=utils.MD_EXTENSIONS_CONF) + + if '.' in cls.name: + self.namespace = cls.name.split('.')[0] + self.name = cls.name.split('.')[1] + self.fqtn = cls.name + else: + self.namespace = namespace.name + self.name = cls.name + self.fqtn = f"{namespace.name}.{self.name}" + + if cls.parent is None or cls.fundamental: + self.parent_fqtn = 'GObject.TypeInstance' + self.parent_cname = 'GTypeInstance*' + self.parent_name = 'TypeInstance' + self.parent_namespace = 'GObject' + elif '.' in cls.parent.name: + self.parent_fqtn = cls.parent.name + self.parent_cname = cls.parent.ctype + self.parent_namespace = self.parent_fqtn.split('.')[0] + self.parent_name = self.parent_fqtn.split('.')[1] + else: + self.parent_cname = cls.parent.ctype + self.parent_name = cls.parent.name + self.parent_namespace = cls.parent.namespace or namespace.name + self.parent_fqtn = f"{self.parent_namespace}.{self.parent_name}" + ++ self.ancestors = [] + if recurse: - self.ancestors = [] + for ancestor_type in cls.ancestors: - if '.' in ancestor_type.name: - ancestor_ns, ancestor_name = ancestor_type.name.split('.') - else: - ancestor_ns = ancestor_type.namespace or namespace.name - ancestor_name = ancestor_type.name - ancestor = namespace.find_class(ancestor_name) - # We don't use real Template objects, here, because it can be - # extremely expensive, unless we add a cache somewhere - if ancestor is not None: - # Set a hard-limit on the number of methods; base types can - # add *a lot* of them; two dozens feel like a good compromise - if len(ancestor.methods) < 24: - methods = [gen_index_func(m, namespace, md) for m in ancestor.methods] - else: - methods = [] - self.ancestors.append({ - "namespace": ancestor_ns, - "name": ancestor_name, - "fqtn": f"{ancestor_ns}.{ancestor_name}", - "type_cname": ancestor_type.base_ctype, - "properties": [gen_index_property(p, namespace, md) for p in ancestor.properties.values()], - "n_properties": len(ancestor.properties), - "signals": [gen_index_signal(s, namespace, md) for s in ancestor.signals.values()], - "n_signals": len(ancestor.signals), - "methods": methods, - "n_methods": len(ancestor.methods), - }) - else: - self.ancestors.append({ - "namespace": ancestor_ns, - "name": ancestor_name, - "fqtn": f"{ancestor_ns}.{ancestor_name}", - "type_cname": ancestor_type.base_ctype, - "properties": [], - "n_properties": 0, - "signals": [], - "n_signals": 0, - "methods": [], - "n_methods": 0, - }) ++ self.ancestors.append(gen_index_ancestor(ancestor_type, namespace, config, md)) ++ ++ if cls.descendants: ++ self.descendants = [] ++ for descendant in cls.descendants: ++ self.descendants.append({ ++ 'name': descendant.name, ++ 'ctype': descendant.ctype, ++ }) + + self.class_name = cls.type_struct + + self.instance_struct = None + if len(cls.fields) != 0: + self.instance_struct = self.class_name + + if cls.type_struct is not None: + self.class_struct = namespace.find_record(cls.type_struct) + else: + self.class_struct = None + + # "Final", in the absence of an actual flag or annotation, + # is determined through an heuristic; if either the instance + # or the class structures are missing or disguised, then the + # type cannot be derived + if self.instance_struct is None or self.class_struct is None or self.class_struct.disguised: + self.final = True + else: + self.final = False + + if cls.doc is not None: + self.summary = utils.preprocess_docs(cls.doc.content, namespace, summary=True, md=md) + self.description = utils.preprocess_docs(cls.doc.content, namespace, md=md) + filename = cls.doc.filename + line = cls.doc.line + if filename.startswith('../'): + filename = filename.replace('../', '') + self.docs_location = (filename, line) + else: + self.description = MISSING_DESCRIPTION + + self.stability = cls.stability + self.attributes = cls.attributes + self.available_since = cls.available_since + if cls.deprecated_since is not None: + (version, msg) = cls.deprecated_since + self.deprecated_since = { + "version": version, + "message": utils.preprocess_docs(msg, namespace, md=md), + } + else: + self.deprecated_since = None + + self.introspectable = cls.introspectable + + self.fields = [] + for field in cls.fields: + if not field.private: + self.fields.append(TemplateField(namespace, field)) + ++ self.properties = [] + if len(cls.properties) != 0: - self.properties = [] + for pname, prop in cls.properties.items(): - self.properties.append(gen_index_property(prop, namespace, md)) ++ if not config.is_hidden(cls.name, "property", pname): ++ self.properties.append(gen_index_property(prop, namespace, md)) + ++ self.signals = [] + if len(cls.signals) != 0: - self.signals = [] + for sname, signal in cls.signals.items(): - self.signals.append(gen_index_signal(signal, namespace, md)) ++ if not config.is_hidden(cls.name, "signal", sname): ++ self.signals.append(gen_index_signal(signal, namespace, md)) + ++ self.ctors = [] + if len(cls.constructors) != 0: - self.ctors = [] + for ctor in cls.constructors: - self.ctors.append(gen_index_func(ctor, namespace, md)) ++ if not config.is_hidden(cls.name, "constructor", ctor.name): ++ self.ctors.append(gen_index_func(ctor, namespace, md)) + ++ self.methods = [] + if len(cls.methods) != 0: - self.methods = [] + for method in cls.methods: - self.methods.append(gen_index_func(method, namespace, md)) ++ if not config.is_hidden(cls.name, "method", method.name): ++ self.methods.append(gen_index_func(method, namespace, md)) + + if self.class_struct is not None: + self.class_ctype = self.class_struct.ctype + self.class_fields = [] + self.class_methods = [] + + for field in self.class_struct.fields: + if not field.private: + self.class_fields.append(TemplateField(namespace, field)) + + for method in self.class_struct.methods: + self.class_methods.append(gen_index_func(method, namespace, md)) + ++ self.interfaces = [] + if len(cls.implements) != 0: - self.interfaces = [] + for iface_type in cls.implements: - if '.' in iface_type.name: - iface_ns, iface_name = iface_type.name.split('.') - else: - iface_ns = iface_type.namespace or namespace.name - iface_name = iface_type.name - iface = namespace.find_interface(iface_name) - if iface is not None: - # Set a hard-limit on the number of methods; base types can - # add *a lot* of them; two dozens feel like a good compromise - if len(iface.methods) < 24: - methods = [gen_index_func(m, namespace, md) for m in iface.methods] - else: - methods = [] - self.interfaces.append({ - "namespace": iface_ns, - "name": iface_name, - "fqtn": f"{iface_ns}.{iface_name}", - "type_cname": iface_type.base_ctype, - "properties": [gen_index_property(p, namespace, md) for p in iface.properties.values()], - "n_properties": len(iface.properties), - "signals": [gen_index_signal(s, namespace, md) for s in iface.signals.values()], - "n_signals": len(iface.signals), - "methods": methods, - "n_methods": len(iface.methods), - }) - else: - self.interfaces.append({ - "namespace": iface_ns, - "name": iface_name, - "fqtn": f"{iface_ns}.{iface_name}", - "type_cname": iface_type.base_ctype, - "properties": [], - "n_properties": 0, - "signals": [], - "n_signals": 0, - "methods": [], - "n_methods": 0, - }) ++ self.interfaces.append(gen_index_implements(iface_type, namespace, config, md)) + ++ self.virtual_methods = [] + if len(cls.virtual_methods) != 0: - self.virtual_methods = [] + for vfunc in cls.virtual_methods: + self.virtual_methods.append(gen_index_func(vfunc, namespace, md)) + ++ self.type_funcs = [] + if len(cls.functions) != 0: - self.type_funcs = [] + for func in cls.functions: - self.type_funcs.append(gen_index_func(func, namespace, md)) ++ if not config.is_hidden(cls.name, "function", func.name): ++ self.type_funcs.append(gen_index_func(func, namespace, md)) ++ ++ @property ++ def show_methods(self): ++ if len(self.methods) > 0: ++ return True ++ for ancestor in self.ancestors: ++ if ancestor["n_methods"] > 0: ++ return True ++ for iface in self.interfaces: ++ if iface["n_methods"] > 0: ++ return True ++ return False ++ ++ @property ++ def show_properties(self): ++ if len(self.properties) > 0: ++ return True ++ for ancestor in self.ancestors: ++ if ancestor["n_properties"] > 0: ++ return True ++ for iface in self.interfaces: ++ if iface["n_properties"] > 0: ++ return True ++ return False ++ ++ @property ++ def show_signals(self): ++ if len(self.signals) > 0: ++ return True ++ for ancestor in self.ancestors: ++ if ancestor["n_signals"] > 0: ++ return True ++ for iface in self.interfaces: ++ if iface["n_signals"] > 0: ++ return True ++ return False + + @property + def c_decl(self): + if self.abstract: + res = [f"abstract class {self.fqtn} : {self.parent_fqtn} {{"] + elif self.final: + res = [f"final class {self.fqtn} : {self.parent_fqtn} {{"] + else: + res = [f"class {self.fqtn} : {self.parent_fqtn} {{"] + n_fields = len(self.fields) + if n_fields > 0: + for (idx, field) in enumerate(self.fields): + if idx < n_fields - 1: + res += [f" {field.name}: {field.type_cname},"] + else: + res += [f" {field.name}: {field.type_cname}"] + else: + res += [" /* No available fields */"] + res += ["}"] + return "\n".join(res) + + @property + def dot(self): + + def fmt_attrs(attrs): + return ','.join(f'{k}="{v}"' for k, v in attrs.items()) + - def add_link(attrs, other): ++ def add_link(attrs, other, fragment): + if other['namespace'] == self.namespace: - attrs['href'] = f"class.{other['name']}.html" ++ attrs['href'] = f"{fragment}.{other['name']}.html" + attrs['class'] = 'link' + else: + attrs['tooltip'] = other['fqtn'] + + ancestors = [] + implements = [] + res = ["graph hierarchy {"] + res.append(" bgcolor=\"transparent\";") + node_attrs = { + 'shape': 'box', + 'style': 'rounded', + 'border': 0 + } + this_attrs = { + 'label': self.type_cname, + 'tooltip': self.type_cname + } + this_attrs.update(node_attrs) + res.append(f" this [{fmt_attrs(this_attrs)}];") + for idx, ancestor in enumerate(self.ancestors): + node_id = f"ancestor_{idx}" + ancestor_attrs = { + 'label': ancestor['type_cname'] + } + ancestor_attrs.update(node_attrs) - add_link(ancestor_attrs, ancestor) ++ add_link(ancestor_attrs, ancestor, 'class') + res.append(f" {node_id} [{fmt_attrs(ancestor_attrs)}];") + ancestors.append(node_id) + ancestors.reverse() + for idx, iface in enumerate(getattr(self, "interfaces", [])): + node_id = f"implements_{idx}" + iface_attrs = { + 'label': iface['type_cname'], + 'fontname': 'sans-serif', + 'shape': 'box', + } - add_link(iface_attrs, iface) ++ add_link(iface_attrs, iface, 'iface') + res.append(f" {node_id} [{fmt_attrs(iface_attrs)}];") + implements.append(node_id) + if len(ancestors) > 0: + res.append(" " + " -- ".join(ancestors) + " -- this;") + for node in implements: + res.append(f" this -- {node} [style=dotted];") + res.append("}") + return "\n".join(res) + + +class TemplateRecord: - def __init__(self, namespace, record): ++ def __init__(self, namespace, record, config): + self.symbol_prefix = f"{namespace.symbol_prefix[0]}_{record.symbol_prefix}" + self.type_cname = record.ctype + self.link_prefix = "struct" + + self.name = record.name + self.namespace = record.name or namespace.name + self.fqtn = f"{self.namespace}.{self.name}" + + md = markdown.Markdown(extensions=utils.MD_EXTENSIONS, + extension_configs=utils.MD_EXTENSIONS_CONF) + + if record.doc is not None: + self.summary = utils.preprocess_docs(record.doc.content, namespace, summary=True, md=md) + self.description = utils.preprocess_docs(record.doc.content, namespace, md=md) + filename = record.doc.filename + line = record.doc.line + if filename.startswith('../'): + filename = filename.replace('../', '') + self.docs_location = (filename, line) + else: + self.description = MISSING_DESCRIPTION + + self.stability = record.stability + self.attributes = record.attributes + self.available_since = record.available_since + if record.deprecated_since is not None: + (version, msg) = record.deprecated_since + self.deprecated_since = { + "version": version, + "message": utils.preprocess_docs(msg, namespace, md=md), + } + else: + self.deprecated_since = None + + self.introspectable = record.introspectable + + self.fields = [] + for field in record.fields: + if not field.private: + self.fields.append(TemplateField(namespace, field)) + + if len(record.constructors) != 0: + self.ctors = [] + for ctor in record.constructors: - self.ctors.append(gen_index_func(ctor, namespace, md)) ++ if not config.is_hidden(record.name, "constructor", ctor.name): ++ self.ctors.append(gen_index_func(ctor, namespace, md)) + + if len(record.methods) != 0: + self.methods = [] + for method in record.methods: - self.methods.append(gen_index_func(method, namespace, md)) ++ if not config.is_hidden(record.name, "method", method.name): ++ self.methods.append(gen_index_func(method, namespace, md)) + + if len(record.functions) != 0: + self.type_funcs = [] + for func in record.functions: - self.type_funcs.append(gen_index_func(func, namespace, md)) ++ if not config.is_hidden(record.name, "function", func.name): ++ self.type_funcs.append(gen_index_func(func, namespace, md)) + + @property + def c_decl(self): + res = [f"struct {self.type_cname} {{"] + n_fields = len(self.fields) + if n_fields > 0: + for field in self.fields: + if field.is_callback: + res += [f" {field.type_cname};"] + else: + res += [f" {field.type_cname} {field.name};"] + else: + res += [" /* No available fields */"] + res += ["}"] + return utils.code_highlight("\n".join(res)) + + +class TemplateUnion: - def __init__(self, namespace, union): ++ def __init__(self, namespace, union, config): + self.symbol_prefix = f"{namespace.symbol_prefix[0]}_{union.symbol_prefix}" + self.type_cname = union.ctype + self.link_prefix = "union" + self.name = union.name + self.namespace = union.namespace or namespace.name + self.fqtn = f"{self.namespace}.{self.name}" + + md = markdown.Markdown(extensions=utils.MD_EXTENSIONS, + extension_configs=utils.MD_EXTENSIONS_CONF) + + if union.doc is not None: + self.summary = utils.preprocess_docs(union.doc.content, namespace, summary=True, md=md) + self.description = utils.preprocess_docs(union.doc.content, namespace, md=md) + filename = union.doc.filename + line = union.doc.line + if filename.startswith('../'): + filename = filename.replace('../', '') + self.docs_location = (filename, line) + else: + self.description = MISSING_DESCRIPTION + + self.stability = union.stability + self.attributes = union.attributes + self.available_since = union.available_since + if union.deprecated_since is not None: + (version, msg) = union.deprecated_since + self.deprecated_since = { + "version": version, + "message": utils.preprocess_docs(msg, namespace, md=md), + } + else: + self.deprecated_since = None + + self.introspectable = union.introspectable + + self.fields = [] + for field in union.fields: + if not field.private: + self.fields.append(TemplateField(namespace, field)) + + if len(union.constructors) != 0: + self.ctors = [] + for ctor in union.constructors: - self.ctors.append(gen_index_func(ctor, namespace, md)) ++ if not config.is_hidden(union.name, "constructor", ctor.name): ++ self.ctors.append(gen_index_func(ctor, namespace, md)) + + if len(union.methods) != 0: + self.methods = [] + for method in union.methods: - self.methods.append(gen_index_func(method, namespace, md)) ++ if not config.is_hidden(union.name, "method", method.name): ++ self.methods.append(gen_index_func(method, namespace, md)) + + if len(union.functions) != 0: + self.type_funcs = [] + for func in union.functions: - self.type_funcs.append(gen_index_func(func, namespace, md)) ++ if not config.is_hidden(union.name, "function", func.name): ++ self.type_funcs.append(gen_index_func(func, namespace, md)) + + @property + def c_decl(self): + res = [f"union {self.type_cname} {{"] + n_fields = len(self.fields) + if n_fields > 0: + for field in self.fields: + if field.is_callback: + res += [f" {field.type_cname};"] + else: + res += [f" {field.type_cname} {field.name};"] + else: + res += [" /* No available fields */"] + res += ["}"] + return utils.code_highlight("\n".join(res)) + + +class TemplateAlias: + def __init__(self, namespace, alias): + self.type_cname = alias.base_ctype + self.target_ctype = alias.target.ctype + self.link_prefix = "alias" + + self.namespace = alias.namespace or namespace.name + self.name = alias.name + self.fqtn = f"{self.namespace}.{self.name}" + + md = markdown.Markdown(extensions=utils.MD_EXTENSIONS, + extension_configs=utils.MD_EXTENSIONS_CONF) + + if alias.doc is not None: + self.summary = utils.preprocess_docs(alias.doc.content, namespace, summary=True, md=md) + self.description = utils.preprocess_docs(alias.doc.content, namespace, md=md) + filename = alias.doc.filename + line = alias.doc.line + if filename.startswith('../'): + filename = filename.replace('../', '') + self.docs_location = (filename, line) + else: + self.description = MISSING_DESCRIPTION + + self.stability = alias.stability + self.attributes = alias.attributes + self.available_since = alias.available_since + self.deprecated_since = alias.deprecated_since + if alias.deprecated_since is not None: + (version, msg) = alias.deprecated_since + self.deprecated_since = { + "version": version, + "message": utils.preprocess_docs(msg, namespace), + } + else: + self.deprecated_since = None + + self.introspectable = alias.introspectable + + @property + def c_decl(self): + return f"typedef {self.target_ctype} {self.type_cname}" + + +class TemplateMember: + def __init__(self, namespace, enum, member): + self.name = member.identifier + self.nick = member.nick + self.value = member.value + if member.doc is not None: + self.description = utils.preprocess_docs(member.doc.content, namespace) + filename = member.doc.filename + line = member.doc.line + if filename.startswith('../'): + filename = filename.replace('../', '') + self.docs_location = (filename, line) + else: + self.description = MISSING_DESCRIPTION + + +class TemplateEnum: - def __init__(self, namespace, enum): ++ def __init__(self, namespace, enum, config): + self.symbol_prefix = None + self.type_cname = enum.ctype + self.bitfield = False + self.error = False + self.domain = None + + self.namespace = namespace.name + self.name = enum.name + self.fqtn = f"{namespace.name}.{enum.name}" + + md = markdown.Markdown(extensions=utils.MD_EXTENSIONS, + extension_configs=utils.MD_EXTENSIONS_CONF) + + if enum.doc is not None: + self.summary = utils.preprocess_docs(enum.doc.content, namespace, summary=True, md=md) + self.description = utils.preprocess_docs(enum.doc.content, namespace, md=md) + filename = enum.doc.filename + line = enum.doc.line + if filename.startswith('../'): + filename = filename.replace('../', '') + self.docs_location = (filename, line) + else: + self.description = MISSING_DESCRIPTION + + self.stability = enum.stability + self.attributes = enum.attributes + self.available_since = enum.available_since + self.deprecated_since = enum.deprecated_since + if enum.deprecated_since is not None: + (version, msg) = enum.deprecated_since + self.deprecated_since = { + "version": version, + "message": utils.preprocess_docs(msg, namespace, md=md), + } + else: + self.deprecated_since = None + + self.introspectable = enum.introspectable + + if isinstance(enum, gir.BitField): + self.link_prefix = "flags" + self.bitfield = True + elif isinstance(enum, gir.ErrorDomain): + self.link_prefix = "error" + self.error = True + self.domain = enum.domain + else: + self.link_prefix = "enum" + + if len(enum.members) != 0: + self.members = [] + for member in enum.members: + self.members.append(TemplateMember(namespace, enum, member)) + + if len(enum.functions) != 0: + self.type_funcs = [] + for func in enum.functions: - self.type_funcs.append(gen_index_func(func, namespace, md)) ++ if not config.is_hidden(enum.name, "function", func.name): ++ self.type_funcs.append(gen_index_func(func, namespace, md)) + + @property + def c_decl(self): + if self.error: + return f"error-domain {self.fqtn}" + elif self.bitfield: + return f"flags {self.fqtn}" + else: + return f"enum {self.fqtn}" + + +class TemplateNamespace: + def __init__(self, namespace): + self.name = namespace.name + self.version = namespace.version + self.symbol_prefix = namespace.symbol_prefix[0] + self.identifier_prefix = namespace.identifier_prefix[0] + + +def _gen_classes(config, theme_config, output_dir, jinja_env, repository, all_classes): + namespace = repository.namespace + + class_tmpl = jinja_env.get_template(theme_config.class_template) + method_tmpl = jinja_env.get_template(theme_config.method_template) + property_tmpl = jinja_env.get_template(theme_config.property_template) + signal_tmpl = jinja_env.get_template(theme_config.signal_template) + class_method_tmpl = jinja_env.get_template(theme_config.class_method_template) + ctor_tmpl = jinja_env.get_template(theme_config.ctor_template) + type_func_tmpl = jinja_env.get_template(theme_config.type_func_template) + vfunc_tmpl = jinja_env.get_template(theme_config.vfunc_template) + + template_classes = [] + + for cls in all_classes: + if config.is_hidden(cls.name): + log.debug(f"Skipping hidden class {cls.name}") + continue + class_file = os.path.join(output_dir, f"class.{cls.name}.html") + log.info(f"Creating class file for {namespace.name}.{cls.name}: {class_file}") + - tmpl = TemplateClass(namespace, cls) ++ tmpl = TemplateClass(namespace, cls, config) + template_classes.append(tmpl) + + if config.show_class_hierarchy: + tmpl.hierarchy_svg = utils.render_dot(tmpl.dot, output_format="svg") + + with open(class_file, "w") as out: + content = class_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + }) + + out.write(content) + + for ctor in cls.constructors: ++ if config.is_hidden(cls.name, "constructor", ctor.name): ++ log.debug(f"Skipping hidden constructor {cls.name}.{ctor.name}") ++ continue + c = TemplateFunction(namespace, ctor) + ctor_file = os.path.join(output_dir, f"ctor.{cls.name}.{ctor.name}.html") + log.debug(f"Creating ctor file for {namespace.name}.{cls.name}.{ctor.name}: {ctor_file}") + + with open(ctor_file, "w") as out: + out.write(ctor_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'type_func': c, + })) + + for method in cls.methods: ++ if config.is_hidden(cls.name, "method", method.name): ++ log.debug(f"Skipping hidden method {cls.name}.{method.name}") ++ continue + m = TemplateMethod(namespace, cls, method) + method_file = os.path.join(output_dir, f"method.{cls.name}.{method.name}.html") + log.debug(f"Creating method file for {namespace.name}.{cls.name}.{method.name}: {method_file}") + + with open(method_file, "w") as out: + out.write(method_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'method': m, + })) + + for prop in cls.properties.values(): + if config.is_hidden(cls.name, 'property', prop.name): + log.debug(f"Skipping hidden property {cls.name}.{prop.name}") + continue + p = TemplateProperty(namespace, cls, prop) + prop_file = os.path.join(output_dir, f"property.{cls.name}.{prop.name}.html") + log.debug(f"Creating property file for {namespace.name}.{cls.name}.{prop.name}: {prop_file}") + + with open(prop_file, "w") as out: + out.write(property_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'property': p, + })) + + for signal in cls.signals.values(): + if config.is_hidden(cls.name, 'signal', signal.name): + log.debug(f"Skipping hidden signal {cls.name}.{signal.name}") + continue + s = TemplateSignal(namespace, cls, signal) + signal_file = os.path.join(output_dir, f"signal.{cls.name}.{signal.name}.html") + log.debug(f"Creating signal file for {namespace.name}.{cls.name}.{signal.name}: {signal_file}") + + with open(signal_file, "w") as out: + out.write(signal_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'signal': s, + })) + + if cls.type_struct is not None: + class_struct = namespace.find_record(cls.type_struct) + for cls_method in class_struct.methods: + c = TemplateClassMethod(namespace, cls, cls_method) + cls_method_file = os.path.join(output_dir, f"class_method.{cls.name}.{cls_method.name}.html") + log.debug(f"Creating class method file for {namespace.name}.{cls.name}.{cls_method.name}: {cls_method_file}") + + with open(cls_method_file, "w") as out: + out.write(class_method_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'class_method': c, + })) + + for vfunc in cls.virtual_methods: + f = TemplateMethod(namespace, cls, vfunc) + vfunc_file = os.path.join(output_dir, f"vfunc.{cls.name}.{vfunc.name}.html") + log.debug(f"Creating vfunc file for {namespace.name}.{cls.name}.{vfunc.name}: {vfunc_file}") + + with open(vfunc_file, "w") as out: + out.write(vfunc_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'vfunc': f, + })) + + for type_func in cls.functions: ++ if config.is_hidden(cls.name, "function", type_func.name): ++ log.debug(f"Skipping hidden type function {cls.name}.{type_func.name}") ++ continue + f = TemplateFunction(namespace, type_func) + type_func_file = os.path.join(output_dir, f"type_func.{cls.name}.{type_func.name}.html") + log.debug(f"Creating type func file for {namespace.name}.{cls.name}.{type_func.name}: {type_func_file}") + + with open(type_func_file, "w") as out: + out.write(type_func_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'type_func': f, + })) + + return template_classes + + +def _gen_interfaces(config, theme_config, output_dir, jinja_env, repository, all_interfaces): + namespace = repository.namespace + + iface_tmpl = jinja_env.get_template(theme_config.interface_template) + method_tmpl = jinja_env.get_template(theme_config.method_template) + property_tmpl = jinja_env.get_template(theme_config.property_template) + signal_tmpl = jinja_env.get_template(theme_config.signal_template) + class_method_tmpl = jinja_env.get_template(theme_config.class_method_template) + type_func_tmpl = jinja_env.get_template(theme_config.type_func_template) + vfunc_tmpl = jinja_env.get_template(theme_config.vfunc_template) + + template_interfaces = [] + + for iface in all_interfaces: + if config.is_hidden(iface.name): + log.debug(f"Skipping hidden interface {iface.name}") + continue + iface_file = os.path.join(output_dir, f"iface.{iface.name}.html") + log.info(f"Creating interface file for {namespace.name}.{iface.name}: {iface_file}") + - tmpl = TemplateInterface(namespace, iface) ++ tmpl = TemplateInterface(namespace, iface, config) + template_interfaces.append(tmpl) + + with open(iface_file, "w") as out: + out.write(iface_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'interface': tmpl, + })) + + for method in iface.methods: ++ if config.is_hidden(iface.name, "method", method.name): ++ log.debug(f"Skipping hidden method {iface.name}.{method.name}") ++ continue + m = TemplateMethod(namespace, iface, method) + method_file = os.path.join(output_dir, f"method.{iface.name}.{method.name}.html") + log.debug(f"Creating method file for {namespace.name}.{iface.name}.{method.name}: {method_file}") + + with open(method_file, "w") as out: + out.write(method_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'method': m, + })) + + for prop in iface.properties.values(): + if config.is_hidden(iface.name, 'property', prop.name): + log.debug(f"Skipping hidden property {iface.name}.{prop.name}") + continue + p = TemplateProperty(namespace, iface, prop) + prop_file = os.path.join(output_dir, f"property.{iface.name}.{prop.name}.html") + log.debug(f"Creating property file for {namespace.name}.{iface.name}.{prop.name}: {prop_file}") + + with open(prop_file, "w") as out: + out.write(property_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'property': p, + })) + + for signal in iface.signals.values(): + if config.is_hidden(iface.name, 'signal', signal.name): + log.debug(f"Skipping hidden property {iface.name}.{signal.name}") + continue + s = TemplateSignal(namespace, iface, signal) + signal_file = os.path.join(output_dir, f"signal.{iface.name}.{signal.name}.html") + log.debug(f"Creating signal file for {namespace.name}.{iface.name}.{signal.name}: {signal_file}") + + with open(signal_file, "w") as out: + out.write(signal_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'signal': s, + })) + + for vfunc in iface.virtual_methods: + v = TemplateMethod(namespace, iface, vfunc) + vfunc_file = os.path.join(output_dir, f"vfunc.{iface.name}.{vfunc.name}.html") + log.debug(f"Creating vfunc file for {namespace.name}.{iface.name}.{vfunc.name}: {vfunc_file}") + + with open(vfunc_file, "w") as out: + out.write(vfunc_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'vfunc': v, + })) + + if iface.type_struct is not None: + iface_struct = namespace.find_record(iface.type_struct) + for cls_method in iface_struct.methods: + m = TemplateClassMethod(namespace, iface, cls_method) + cls_method_file = os.path.join(output_dir, f"class_method.{iface.name}.{cls_method.name}.html") + log.debug(f"Creating class method file for {namespace.name}.{iface.name}.{cls_method.name}: {cls_method_file}") + + with open(cls_method_file, "w") as out: + out.write(class_method_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'class_method': m, + })) + + for type_func in iface.functions: ++ if config.is_hidden(iface.name, "function", type_func.name): ++ log.debug(f"Skipping hidden type function {iface.name}.{type_func.name}") ++ continue + f = TemplateFunction(namespace, type_func) + type_func_file = os.path.join(output_dir, f"type_func.{iface.name}.{type_func.name}.html") + log.debug(f"Creating type func file for {namespace.name}.{iface.name}.{type_func.name}: {type_func_file}") + + with open(type_func_file, "w") as out: + out.write(type_func_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'type_func': f, + })) + + return template_interfaces + + +def _gen_enums(config, theme_config, output_dir, jinja_env, repository, all_enums): + namespace = repository.namespace + + enum_tmpl = jinja_env.get_template(theme_config.enum_template) + type_func_tmpl = jinja_env.get_template(theme_config.type_func_template) + + template_enums = [] + + for enum in all_enums: + if config.is_hidden(enum.name): + log.debug(f"Skipping hidden enum {enum.name}") + continue + enum_file = os.path.join(output_dir, f"enum.{enum.name}.html") + log.info(f"Creating enum file for {namespace.name}.{enum.name}: {enum_file}") + - tmpl = TemplateEnum(namespace, enum) ++ tmpl = TemplateEnum(namespace, enum, config) + template_enums.append(tmpl) + + with open(enum_file, "w") as out: + out.write(enum_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'enum': tmpl, + })) + + for type_func in enum.functions: + f = TemplateFunction(namespace, type_func) + type_func_file = os.path.join(output_dir, f"type_func.{enum.name}.{type_func.name}.html") + log.debug(f"Creating type func file for {namespace.name}.{enum.name}.{type_func.name}: {type_func_file}") + + with open(type_func_file, "w") as out: + out.write(type_func_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'type_func': f, + })) + + return template_enums + + +def _gen_bitfields(config, theme_config, output_dir, jinja_env, repository, all_enums): + namespace = repository.namespace + + enum_tmpl = jinja_env.get_template(theme_config.flags_template) + type_func_tmpl = jinja_env.get_template(theme_config.type_func_template) + + template_bitfields = [] + + for enum in all_enums: + if config.is_hidden(enum.name): + log.debug(f"Skipping hidden bitfield {enum.name}") + continue + enum_file = os.path.join(output_dir, f"flags.{enum.name}.html") + log.info(f"Creating enum file for {namespace.name}.{enum.name}: {enum_file}") + - tmpl = TemplateEnum(namespace, enum) ++ tmpl = TemplateEnum(namespace, enum, config) + template_bitfields.append(tmpl) + + with open(enum_file, "w") as out: + out.write(enum_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'enum': tmpl, + })) + + for type_func in enum.functions: + f = TemplateFunction(namespace, type_func) + type_func_file = os.path.join(output_dir, f"type_func.{enum.name}.{type_func.name}.html") + log.debug(f"Creating type func file for {namespace.name}.{enum.name}.{type_func.name}: {type_func_file}") + + with open(type_func_file, "w") as out: + out.write(type_func_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'type_func': f, + })) + + return template_bitfields + + +def _gen_domains(config, theme_config, output_dir, jinja_env, repository, all_enums): + namespace = repository.namespace + + enum_tmpl = jinja_env.get_template(theme_config.error_template) + type_func_tmpl = jinja_env.get_template(theme_config.type_func_template) + + template_domains = [] + + for enum in all_enums: + if config.is_hidden(enum.name): + log.debug(f"Skipping hidden domain {enum.name}") + continue + enum_file = os.path.join(output_dir, f"error.{enum.name}.html") + log.info(f"Creating enum file for {namespace.name}.{enum.name}: {enum_file}") + - tmpl = TemplateEnum(namespace, enum) ++ tmpl = TemplateEnum(namespace, enum, config) + template_domains.append(tmpl) + + with open(enum_file, "w") as out: + out.write(enum_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'enum': tmpl, + })) + + for type_func in enum.functions: + f = TemplateFunction(namespace, type_func) + type_func_file = os.path.join(output_dir, f"type_func.{enum.name}.{type_func.name}.html") + log.debug(f"Creating type func file for {namespace.name}.{enum.name}.{type_func.name}: {type_func_file}") + + with open(type_func_file, "w") as out: + out.write(type_func_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'type_func': f, + })) + + return template_domains + + +def _gen_constants(config, theme_config, output_dir, jinja_env, repository, all_constants): + namespace = repository.namespace + + const_tmpl = jinja_env.get_template(theme_config.constant_template) + + template_constants = [] + + for const in all_constants: + if config.is_hidden(const.name): + log.debug(f"Skipping hidden constant {const.name}") + continue + const_file = os.path.join(output_dir, f"const.{const.name}.html") + log.info(f"Creating constant file for {namespace.name}.{const.name}: {const_file}") + + tmpl = TemplateConstant(namespace, const) + template_constants.append(tmpl) + + with open(const_file, "w") as out: + out.write(const_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'constant': tmpl, + })) + + return template_constants + + +def _gen_aliases(config, theme_config, output_dir, jinja_env, repository, all_aliases): + namespace = repository.namespace + + alias_tmpl = jinja_env.get_template(theme_config.alias_template) + + template_aliases = [] + + for alias in all_aliases: + if config.is_hidden(alias.name): + log.debug(f"Skipping hidden alias {alias.name}") + continue + alias_file = os.path.join(output_dir, f"alias.{alias.name}.html") + log.info(f"Creating alias file for {namespace.name}.{alias.name}: {alias_file}") + + tmpl = TemplateAlias(namespace, alias) + template_aliases.append(tmpl) + + with open(alias_file, "w") as out: + content = alias_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'struct': tmpl, + }) + + out.write(content) + + return template_aliases + + +def _gen_records(config, theme_config, output_dir, jinja_env, repository, all_records): + namespace = repository.namespace + + record_tmpl = jinja_env.get_template(theme_config.record_template) + method_tmpl = jinja_env.get_template(theme_config.method_template) + type_func_tmpl = jinja_env.get_template(theme_config.type_func_template) + + template_records = [] + + for record in all_records: + if config.is_hidden(record.name): + log.debug(f"Skipping hidden record {record.name}") + continue + record_file = os.path.join(output_dir, f"struct.{record.name}.html") + log.info(f"Creating record file for {namespace.name}.{record.name}: {record_file}") + - tmpl = TemplateRecord(namespace, record) ++ tmpl = TemplateRecord(namespace, record, config) + template_records.append(tmpl) + + with open(record_file, "w") as out: + content = record_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'struct': tmpl, + }) + + out.write(content) + + for ctor in record.constructors: ++ if config.is_hidden(record.name, "constructor", ctor.name): ++ log.debug(f"Skipping hidden constructor {record.name}.{ctor.name}") ++ continue + c = TemplateFunction(namespace, ctor) + ctor_file = os.path.join(output_dir, f"ctor.{record.name}.{ctor.name}.html") + log.debug(f"Creating ctor file for {namespace.name}.{record.name}.{ctor.name}: {ctor_file}") + + with open(ctor_file, "w") as out: + out.write(type_func_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'type_func': c, + })) + + for method in record.methods: ++ if config.is_hidden(record.name, "method", method.name): ++ log.debug(f"Skipping hidden method {record.name}.{method.name}") ++ continue + m = TemplateMethod(namespace, record, method) + method_file = os.path.join(output_dir, f"method.{record.name}.{method.name}.html") + log.debug(f"Creating method file for {namespace.name}.{record.name}.{method.name}: {method_file}") + + with open(method_file, "w") as out: + out.write(method_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'method': m, + })) + + for type_func in record.functions: ++ if config.is_hidden(record.name, "method", type_func.name): ++ log.debug(f"Skipping hidden type function {record.name}.{type_func.name}") ++ continue + f = TemplateFunction(namespace, type_func) + type_func_file = os.path.join(output_dir, f"type_func.{record.name}.{type_func.name}.html") + log.debug(f"Creating type func file for {namespace.name}.{record.name}.{type_func.name}: {type_func_file}") + + with open(type_func_file, "w") as out: + out.write(type_func_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'type_func': f, + })) + + return template_records + + +def _gen_unions(config, theme_config, output_dir, jinja_env, repository, all_unions): + namespace = repository.namespace + + union_tmpl = jinja_env.get_template(theme_config.union_template) + method_tmpl = jinja_env.get_template(theme_config.method_template) + type_func_tmpl = jinja_env.get_template(theme_config.type_func_template) + + template_unions = [] + + for union in all_unions: + if config.is_hidden(union.name): + log.debug(f"Skipping hidden union {union.name}") + continue + union_file = os.path.join(output_dir, f"union.{union.name}.html") + log.info(f"Creating union file for {namespace.name}.{union.name}: {union_file}") + - tmpl = TemplateUnion(namespace, union) ++ tmpl = TemplateUnion(namespace, union, config) + template_unions.append(tmpl) + + with open(union_file, "w") as out: + content = union_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'struct': tmpl, + }) + + out.write(content) + + for ctor in union.constructors: ++ if config.is_hidden(union.name, "constructor", ctor.name): ++ log.debug(f"Skipping hidden constructor {union.name}.{ctor.name}") ++ continue + c = TemplateFunction(namespace, ctor) + ctor_file = os.path.join(output_dir, f"ctor.{union.name}.{ctor.name}.html") + log.debug(f"Creating ctor file for {namespace.name}.{union.name}.{ctor.name}: {ctor_file}") + + with open(ctor_file, "w") as out: + out.write(type_func_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'type_func': c, + })) + + for method in union.methods: ++ if config.is_hidden(union.name, "method", method.name): ++ log.debug(f"Skipping hidden method {union.name}.{method.name}") ++ continue + m = TemplateMethod(namespace, union, method) + method_file = os.path.join(output_dir, f"method.{union.name}.{method.name}.html") + log.debug(f"Creating method file for {namespace.name}.{union.name}.{method.name}: {method_file}") + + with open(method_file, "w") as out: + out.write(method_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'method': m, + })) + + for type_func in union.functions: ++ if config.is_hidden(union.name, "function", type_func.name): ++ log.debug(f"Skipping hidden type function {union.name}.{type_func.name}") ++ continue + f = TemplateFunction(namespace, type_func) + type_func_file = os.path.join(output_dir, f"type_func.{union.name}.{type_func.name}.html") + log.debug(f"Creating type func file for {namespace.name}.{union.name}.{type_func.name}: {type_func_file}") + + with open(type_func_file, "w") as out: + out.write(type_func_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'class': tmpl, + 'type_func': f, + })) + + return template_unions + + +def _gen_functions(config, theme_config, output_dir, jinja_env, repository, all_functions): + namespace = repository.namespace + + func_tmpl = jinja_env.get_template(theme_config.func_template) + + template_functions = [] + + for func in all_functions: + if config.is_hidden(func.name): + log.debug(f"Skipping hidden function {func.name}") + continue + func_file = os.path.join(output_dir, f"func.{func.name}.html") + log.info(f"Creating function file for {namespace.name}.{func.name}: {func_file}") + + tmpl = TemplateFunction(namespace, func) + template_functions.append(tmpl) + + with open(func_file, "w") as out: + content = func_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'func': tmpl, + }) + + out.write(content) + + return template_functions + + +def _gen_callbacks(config, theme_config, output_dir, jinja_env, repository, all_callbacks): + namespace = repository.namespace + + func_tmpl = jinja_env.get_template(theme_config.func_template) + + template_callbacks = [] + + for func in all_callbacks: + if config.is_hidden(func.name): + log.debug(f"Skipping hidden callback {func.name}") + continue + func_file = os.path.join(output_dir, f"callback.{func.name}.html") + log.info(f"Creating callback file for {namespace.name}.{func.name}: {func_file}") + + tmpl = TemplateCallback(namespace, func) + template_callbacks.append(tmpl) + + with open(func_file, "w") as out: + content = func_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'func': tmpl, + }) + + out.write(content) + + return template_callbacks + + +def _gen_function_macros(config, theme_config, output_dir, jinja_env, repository, all_functions): + namespace = repository.namespace + + func_tmpl = jinja_env.get_template(theme_config.func_template) + + template_functions = [] + + for func in all_functions: + if config.is_hidden(func.name): + log.debug(f"Skipping hidden macro {func.name}") + continue + func_file = os.path.join(output_dir, f"func.{func.name}.html") + log.info(f"Creating function macro file for {namespace.name}.{func.name}: {func_file}") + + tmpl = TemplateFunction(namespace, func) + template_functions.append(tmpl) + + with open(func_file, "w") as out: + content = func_tmpl.render({ + 'CONFIG': config, + 'namespace': namespace, + 'func': tmpl, + }) + + out.write(content) + + return template_functions + + - def gen_content_files(config, theme_config, content_dir, output_dir, jinja_env, namespace): ++def gen_content_files(config, theme_config, content_dirs, output_dir, jinja_env, namespace): + content_files = [] + + content_tmpl = jinja_env.get_template(theme_config.content_template) + md = markdown.Markdown(extensions=utils.MD_EXTENSIONS, extension_configs=utils.MD_EXTENSIONS_CONF) + + for file_name in config.content_files: - src_file = os.path.join(content_dir, file_name) ++ src_file = utils.find_extra_content_file(content_dirs, file_name) + + src_data = "" + with open(src_file, encoding='utf-8') as infile: + source = [] + for line in infile: + source.append(line) + src_data = "".join(source) + + dst_data = utils.preprocess_docs(src_data, namespace, md=md) + title = "\n".join(md.Meta.get("title", ["Unknown document"])) + + content_file = file_name.replace(".md", ".html") + dst_file = os.path.join(output_dir, content_file) + + content = { + "abs_input_file": src_file, + "abs_output_file": dst_file, + "source_file": file_name, + "output_file": content_file, + "meta": md.Meta, + "title": title, + "data": dst_data, + } + + log.info(f"Generating content file {file_name}: {dst_file}") + with open(dst_file, "w", encoding='utf-8') as outfile: + outfile.write(content_tmpl.render({ + "CONFIG": config, + "namespace": namespace, + "content": content, + })) + + content_files.append({ + "title": title, + "href": content_file, + }) + + md.reset() + + return content_files + + - def gen_content_images(config, content_dir, output_dir): ++def gen_content_images(config, content_dirs, output_dir): + content_images = [] + + for image_file in config.content_images: - infile = os.path.join(content_dir, image_file) ++ infile = utils.find_extra_content_file(content_dirs, image_file) + outfile = os.path.join(output_dir, os.path.basename(image_file)) + log.debug(f"Adding extra content image: {infile} -> {outfile}") + content_images += [(infile, outfile)] + + return content_images + + +def gen_types_hierarchy(config, theme_config, output_dir, jinja_env, repository): + # All GObject sub-types + objects_tree = repository.get_class_hierarchy(root="GObject.Object") + + # All GTypeInstance sub-types + typed_tree = repository.get_class_hierarchy() + + res = ["

Classes Hierarchy

"] + + def dump_tree(node, out): + for k in node: + if '.' in k: + out.append(f'
  • {k}') + else: + out.append(f'
  • {k}') + if len(node[k]) != 0: + out.append('
      ') + dump_tree(node[k], out) + out.append("
    ") + out.append("
  • ") + + if len(objects_tree) != 0: + res += ["
    "] + res += ["
      "] + res += ["
    • GObject
      • "] + dump_tree(objects_tree, res) + res += ["
      "] + res += ["
    "] + res += ["
    "] + + if len(typed_tree) != 0: + res += ["
    "] + res += ["
      "] + res += ["
    • GTypeInstance
      • "] + dump_tree(typed_tree, res) + res += ["
      "] + res += ["
    "] + res += ["
    "] + + content = { + "output_file": "classes_hierarchy.html", + "meta": { + "keywords": "types, hierarchy, classes", + }, + "title": "Classes Hierarchy", + "data": Markup("\n".join(res)), + } + + content_tmpl = jinja_env.get_template(theme_config.content_template) + + namespace = repository.namespace + + dst_file = os.path.join(output_dir, content["output_file"]) + log.info(f"Generating type hierarchy file: {dst_file}") + with open(dst_file, "w") as outfile: + outfile.write(content_tmpl.render({ + "CONFIG": config, + "namespace": namespace, + "content": content, + })) + + return { + "title": content["title"], + "href": content["output_file"], + } + + +def gen_devhelp(config, repository, namespace, symbols, content_files): + book = etree.Element('book') + book.set("xmlns", "http://www.devhelp.net/book") + book.set("title", f"{namespace.name}-{namespace.version} Reference Manual") + book.set("link", "index.html") + book.set("author", f"{config.authors}") + book.set("name", f"{namespace.name}") + book.set("version", "2") + book.set("language", "c") + + chapters = etree.SubElement(book, 'chapters') + + for f in content_files: + sub = etree.SubElement(chapters, 'sub') + sub.set("name", f["title"]) + sub.set("link", f["href"]) + + for section, types in symbols.items(): + if len(types) == 0: + continue + + sub = etree.SubElement(chapters, "sub") + sub.set("name", section.replace("_", " ").capitalize()) + sub.set("link", f"index.html#{section}") + + for t in types: + sub_section = etree.SubElement(sub, "sub") + sub_section.set("name", t.name) + sub_section.set("link", f"{FRAGMENT[section]}.{t.name}.html") + + functions = etree.SubElement(book, "functions") + for section, types in symbols.items(): + if len(types) == 0: + continue + + for t in types: + if section in ["functions", "function_macros"]: + keyword = etree.SubElement(functions, "keyword") + if section == "functions": + keyword.set("type", "function") + else: + keyword.set("type", "macro") + keyword.set("name", t.identifier) + keyword.set("link", f"func.{t.name}.html") + if t.available_since is not None: + keyword.set("since", t.available_since) + if t.deprecated_since is not None and t.deprecated_since["version"] is not None: + keyword.set("deprecated", t.deprecated_since["version"]) + continue + + if section == "constants": + keyword = etree.SubElement(functions, "keyword") + keyword.set("type", "constant") + keyword.set("name", t.identifier) + keyword.set("link", f"constant.{t.name}.html") + if t.available_since is not None: + keyword.set("since", t.available_since) + if t.deprecated_since is not None and t.deprecated_since["version"] is not None: + keyword.set("deprecated", t.deprecated_since["version"]) + continue + + if section in ["aliases", "bitfields", "classes", "domains", "enums", "interfaces", "structs", "unions"]: + # Skip anonymous types; e.g. GValue's anonymous union + if t.type_cname is None: + continue + keyword = etree.SubElement(functions, "keyword") + if section == "aliases": + keyword.set("type", "typedef") + elif section in ["bitfields", "domains", "enums"]: + keyword.set("type", "enum") + elif section == "unions": + keyword.set("type", "union") + else: + keyword.set("type", "struct") + keyword.set("name", t.type_cname) + keyword.set("link", f"{FRAGMENT[section]}.{t.name}.html") + if t.available_since is not None: + keyword.set("since", t.available_since) + if t.deprecated_since is not None and t.deprecated_since["version"] is not None: + keyword.set("deprecated", t.deprecated_since["version"]) + + for m in getattr(t, "members", []): + keyword = etree.SubElement(functions, "keyword") + keyword.set("type", "constant") + keyword.set("name", m.name) + keyword.set("link", f"{FRAGMENT[section]}.{t.name}.html") + + for f in getattr(t, "fields", []): + keyword = etree.SubElement(functions, "keyword") + keyword.set("type", "member") + keyword.set("name", f"{t.type_cname}.{f.name}") + keyword.set("link", f"{FRAGMENT[section]}.{t.name}.html") + + class_struct = getattr(t, "class_struct", None) + if class_struct is not None: + for f in getattr(class_struct, "fields", []): + keyword = etree.SubElement(functions, "keyword") + keyword.set("type", "member") + keyword.set("name", f"{t.class_name}.{f.name}") + if section == "class": + keyword.set("link", f"class.{t.name}.html#class-struct") + elif section == "interface": + keyword.set("link", f"iface.{t.name}.html#interface-struct") + else: + keyword.set("link", f"{FRAGMENT[section]}.{t.name}.html") + + for m in getattr(t, "methods", []): + keyword = etree.SubElement(functions, "keyword") + keyword.set("type", "function") + keyword.set("name", m['identifier']) + keyword.set("link", f"method.{t.name}.{m['name']}.html") + if m["available_since"] is not None: + keyword.set("since", m["available_since"]) + if m["deprecated_since"] is not None: + keyword.set("deprecated", m["deprecated_since"]) + + for c in getattr(t, "ctors", []): + keyword = etree.SubElement(functions, "keyword") + keyword.set("type", "function") + keyword.set("name", c['identifier']) + keyword.set("link", f"ctor.{t.name}.{c['name']}.html") + if c["available_since"] is not None: + keyword.set("since", c["available_since"]) + if c["deprecated_since"] is not None: + keyword.set("deprecated", c["deprecated_since"]) + + for f in getattr(t, "type_funcs", []): + keyword = etree.SubElement(functions, "keyword") + keyword.set("type", "function") + keyword.set("name", f['identifier']) + keyword.set("link", f"type_func.{t.name}.{f['name']}.html") + if f["available_since"] is not None: + keyword.set("since", f["available_since"]) + if f["deprecated_since"] is not None: + keyword.set("deprecated", f["deprecated_since"]) + + for m in getattr(t, "class_methods", []): + keyword = etree.SubElement(functions, "keyword") + keyword.set("type", "function") + keyword.set("name", m['identifier']) + keyword.set("link", f"class_method.{t.name}.{m['name']}.html") + if m["available_since"] is not None: + keyword.set("since", m["available_since"]) + if m["deprecated_since"] is not None: + keyword.set("deprecated", m["deprecated_since"]) + + for p in getattr(t, "properties", []): + keyword = etree.SubElement(functions, "keyword") + keyword.set("type", "property") + keyword.set("name", f"The {t.type_cname}:{p['name']} property") + keyword.set("link", f"property.{t.name}.{p['name']}.html") + if p["available_since"] is not None: + keyword.set("since", p["available_since"]) + if p["deprecated_since"] is not None: + keyword.set("deprecated", p["deprecated_since"]) + + for s in getattr(t, "signals", []): + keyword = etree.SubElement(functions, "keyword") + keyword.set("type", "signal") + keyword.set("name", f"The {t.type_cname}::{s['name']} signal") + keyword.set("link", f"signal.{t.name}.{s['name']}.html") + if s["available_since"] is not None: + keyword.set("since", s["available_since"]) + if s["deprecated_since"] is not None: + keyword.set("deprecated", s["deprecated_since"]) + + return etree.ElementTree(book) + + - def gen_reference(config, options, repository, templates_dir, theme_config, content_dir, output_dir): ++def gen_reference(config, options, repository, templates_dir, theme_config, content_dirs, output_dir): + theme_dir = os.path.join(templates_dir, theme_config.name.lower()) + log.debug(f"Loading jinja templates from {theme_dir}") + + fs_loader = jinja2.FileSystemLoader(theme_dir) + jinja_env = jinja2.Environment(loader=fs_loader, autoescape=jinja2.select_autoescape(['html'])) + + namespace = repository.namespace + + symbols = { + "aliases": sorted(namespace.get_aliases(), key=lambda alias: alias.name.lower()), + "bitfields": sorted(namespace.get_bitfields(), key=lambda bitfield: bitfield.name.lower()), + "callbacks": sorted(namespace.get_callbacks(), key=lambda callback: callback.name.lower()), + "classes": sorted(namespace.get_classes(), key=lambda cls: cls.name.lower()), + "constants": sorted(namespace.get_constants(), key=lambda const: const.name.lower()), + "domains": sorted(namespace.get_error_domains(), key=lambda domain: domain.name.lower()), + "enums": sorted(namespace.get_enumerations(), key=lambda enum: enum.name.lower()), + "functions": sorted(namespace.get_functions(), key=lambda func: func.name.lower()), + "function_macros": sorted(namespace.get_effective_function_macros(), key=lambda func: func.name.lower()), + "interfaces": sorted(namespace.get_interfaces(), key=lambda interface: interface.name.lower()), + "structs": sorted(namespace.get_effective_records(), key=lambda record: record.name.lower()), + "unions": sorted(namespace.get_unions(), key=lambda union: union.name.lower()), + } + + all_indices = { + "aliases": _gen_aliases, + "bitfields": _gen_bitfields, + "callbacks": _gen_callbacks, + "classes": _gen_classes, + "constants": _gen_constants, + "domains": _gen_domains, + "enums": _gen_enums, + "functions": _gen_functions, + "function_macros": _gen_function_macros, + "interfaces": _gen_interfaces, + "structs": _gen_records, + "unions": _gen_unions, + } + + if options.no_namespace_dir: + ns_dir = output_dir + else: + ns_dir = os.path.join(output_dir, f"{namespace.name}-{namespace.version}") + + log.debug(f"Creating output path for the namespace: {ns_dir}") + os.makedirs(ns_dir, exist_ok=True) + - content_files = gen_content_files(config, theme_config, content_dir, ns_dir, jinja_env, namespace) - content_images = gen_content_images(config, content_dir, ns_dir) ++ content_files = gen_content_files(config, theme_config, content_dirs, ns_dir, jinja_env, namespace) ++ content_images = gen_content_images(config, content_dirs, ns_dir) + content_files.append(gen_types_hierarchy(config, theme_config, ns_dir, jinja_env, repository)) + + if options.sections == [] or options.sections == ["all"]: + gen_indices = list(all_indices.keys()) + elif options.sections == ["none"]: + gen_indices = [] + else: + gen_indices = options.sections + + log.info(f"Generating references for: {gen_indices}") + + template_symbols = {} + + # Each section is isolated, so we run it into a thread pool + with concurrent.futures.ThreadPoolExecutor() as executor: + futures_to_section = {} + for section in gen_indices: + s = symbols.get(section, []) + if s is None: + log.debug(f"No symbols for section {section}") + continue + + generator = all_indices.get(section, None) + if generator is None: + log.debug(f"No generator for section {section}") + continue + + f = executor.submit(generator, config, theme_config, ns_dir, jinja_env, repository, s) + futures_to_section[f] = section + + for future in concurrent.futures.as_completed(futures_to_section): + section = futures_to_section[future] + try: + res = future.result() + except Exception as e: + if log.log_fatal_warnings: + import traceback + traceback.print_exc() + log.warning(f"Section {section} raised {e}") + else: + template_symbols[section] = res + + # The concurrent processing introduces non-determinism. Ensure iteration order is reproducible + # by sorting by key. This has virtually no overhead since the values are not copied. + template_symbols = dict(sorted(template_symbols.items())) + + ns_tmpl = jinja_env.get_template(theme_config.namespace_template) + ns_file = os.path.join(ns_dir, "index.html") + log.info(f"Creating namespace index file for {namespace.name}-{namespace.version}: {ns_file}") + with open(ns_file, "w") as out: + out.write(ns_tmpl.render({ + "CONFIG": config, + "repository": repository, + "namespace": namespace, + "symbols": template_symbols, + "content_files": content_files, + })) + + if config.devhelp: + # Devhelp expects the book file to have the same basename as the directory it is in. + devhelp_file = os.path.join(ns_dir, f"{os.path.basename(ns_dir)}.devhelp2") + log.info(f"Creating DevHelp file for {namespace.name}-{namespace.version}: {devhelp_file}") + res = gen_devhelp(config, repository, namespace, template_symbols, content_files) + res.write(devhelp_file, encoding="UTF-8") + + if config.search_index: - gdgenindices.gen_indices(config, repository, content_dir, ns_dir) ++ gdgenindices.gen_indices(config, repository, content_dirs, ns_dir) + + copy_files = [] + if theme_config.css is not None: + style_src = os.path.join(theme_dir, theme_config.css) + style_dst = os.path.join(ns_dir, theme_config.css) + copy_files.append((style_src, style_dst)) + + for extra_file in theme_config.extra_files: + src = os.path.join(theme_dir, extra_file) + dst = os.path.join(ns_dir, extra_file) + copy_files.append((src, dst)) + + if config.urlmap_file is not None: - src = os.path.join(content_dir, config.urlmap_file) ++ src = utils.find_extra_content_file(content_dirs, config.urlmap_file) + dst = os.path.join(ns_dir, os.path.basename(config.urlmap_file)) + copy_files.append((src, dst)) + + copy_files.extend(content_images) + + def copy_worker(src, dst): + log.info(f"Copying file {src}: {dst}") + dst_dir = os.path.dirname(dst) + os.makedirs(dst_dir, exist_ok=True) + shutil.copy(src, dst) + + with concurrent.futures.ThreadPoolExecutor() as executor: + for (src, dst) in copy_files: + executor.submit(copy_worker, src, dst) + + +def add_args(parser): + parser.add_argument("--add-include-path", action="append", dest="include_paths", default=[], + help="include paths for other GIR files") + parser.add_argument("-C", "--config", metavar="FILE", help="the configuration file") + parser.add_argument("--dry-run", action="store_true", help="parses the GIR file without generating files") + parser.add_argument("--templates-dir", default=None, help="the base directory with the theme templates") - parser.add_argument("--content-dir", default=None, help="the base directory with the extra content") ++ parser.add_argument("--content-dir", action="append", dest="content_dirs", default=[], ++ help="the base directories with the extra content") + parser.add_argument("--theme-name", default="basic", help="the theme to use") + parser.add_argument("--output-dir", default=None, help="the output directory for the index files") - parser.add_argument("--no-namespace-dir", action="store_true", help="do not create a namespace directory under the output directory") ++ parser.add_argument("--no-namespace-dir", action="store_true", ++ help="do not create a namespace directory under the output directory") + parser.add_argument("--section", action="append", dest="sections", default=[], help="the sections to generate, or 'all'") + parser.add_argument("infile", metavar="GIRFILE", type=argparse.FileType('r', encoding='UTF-8'), + default=sys.stdin, help="the GIR file to parse") + + +def run(options): + log.info(f"Loading config file: {options.config}") + + conf = config.GIDocConfig(options.config) + + output_dir = options.output_dir or os.getcwd() - content_dir = options.content_dir or os.getcwd() ++ ++ content_dirs = options.content_dirs ++ if content_dirs == []: ++ content_dirs = [os.getcwd()] + + if options.templates_dir is not None: + templates_dir = options.templates_dir + else: + templates_dir = conf.get_templates_dir() + if templates_dir is None: + templates_dir = os.path.join(os.path.dirname(__file__), 'templates') + + theme_name = conf.get_theme_name(default=options.theme_name) + theme_conf = config.GITemplateConfig(templates_dir, theme_name) + + log.debug(f"Templates directory: {templates_dir}") + log.info(f"Theme name: {theme_conf.name}") + log.info(f"Output directory: {output_dir}") + + paths = [] + paths.extend(options.include_paths) + paths.extend(utils.default_search_paths()) + log.debug(f"Search paths: {paths}") + + log.info("Parsing GIR file") + parser = gir.GirParser(search_paths=paths) + parser.parse(options.infile) + + if not options.dry_run: + log.checkpoint() - gen_reference(conf, options, parser.get_repository(), templates_dir, theme_conf, content_dir, output_dir) ++ gen_reference(conf, options, parser.get_repository(), templates_dir, theme_conf, content_dirs, output_dir) + + return 0 diff --cc subprojects/gi-docgen/gidocgen/gdgenindices.py index da8846b9e4,0000000000..e759c2db70 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/gdgenindices.py +++ b/subprojects/gi-docgen/gidocgen/gdgenindices.py @@@ -1,794 -1,0 +1,838 @@@ +# SPDX-FileCopyrightText: 2020 GNOME Foundation +# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +import argparse +import json +import os +import sys + +from . import config, core, gir, log, porter, utils + + +HELP_MSG = "Generates the symbol indices for search" + +MISSING_DESCRIPTION = "No description available." + + +def add_index_terms(index, terms, docid): + for term in terms: + docs = index.setdefault(term, []) + if docid not in docs: + docs.append(docid) + + +def _gen_aliases(config, stemmer, index, repository, symbols): + index_symbols = index["symbols"] + index_terms = index["terms"] + + for alias in symbols: + if config.is_hidden(alias.name): + log.debug(f"Skipping hidden type {alias.name}") + continue + idx = len(index_symbols) + if alias.doc is not None: + description = alias.doc.content + else: + description = MISSING_DESCRIPTION + index_symbols.append({ + "type": "alias", + "name": alias.name, + "ctype": alias.base_ctype, + "summary": utils.preprocess_docs(description, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [alias.base_ctype.lower()], idx) + add_index_terms(index_terms, utils.index_identifier(alias.name, stemmer), idx) + add_index_terms(index_terms, utils.index_description(description, stemmer), idx) + + +def _gen_bitfields(config, stemmer, index, repository, symbols): + index_symbols = index["symbols"] + index_terms = index["terms"] + + for bitfield in symbols: + if config.is_hidden(bitfield.name): + log.debug(f"Skipping hidden type {bitfield.name}") + continue + idx = len(index_symbols) + if bitfield.doc is not None: + description = bitfield.doc.content + else: + description = MISSING_DESCRIPTION + index_symbols.append({ + "type": "bitfield", + "name": bitfield.name, + "ctype": bitfield.base_ctype, + "summary": utils.preprocess_docs(description, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [bitfield.base_ctype.lower()], idx) + add_index_terms(index_terms, utils.index_identifier(bitfield.name, stemmer), idx) + add_index_terms(index_terms, utils.index_description(description, stemmer), idx) + + for member in bitfield.members: + add_index_terms(index_terms, [member.name], idx) + if member.doc is not None: + add_index_terms(index_terms, utils.index_description(member.doc.content, stemmer), idx) + + for func in bitfield.functions: + func_idx = len(index_symbols) + if func.doc is not None: + func_desc = func.doc.content + else: + func_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "type_func", + "name": func.name, + "type_name": bitfield.name, + "ident": func.identifier, + "summary": utils.preprocess_docs(func_desc, repository.namespace, summary=True, plain=True) + }) + add_index_terms(index_terms, [func.identifier], func_idx) + add_index_terms(index_terms, utils.index_symbol(func.name, stemmer), func_idx) + add_index_terms(index_terms, utils.index_description(func_desc, stemmer), func_idx) + + +def _gen_callbacks(config, stemmer, index, repository, symbols): + index_symbols = index["symbols"] + index_terms = index["terms"] + + for callback in symbols: + if config.is_hidden(callback.name): + log.debug(f"Skipping hidden callback {callback.name}") + continue + idx = len(index_symbols) + if callback.doc is not None: + cb_desc = callback.doc.content + else: + cb_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "callback", + "name": callback.name, ++ "ctype": callback.base_ctype, + "summary": utils.preprocess_docs(cb_desc, repository.namespace, summary=True, plain=True), + }) - add_index_terms(index_terms, [callback.name.lower()], idx) ++ add_index_terms(index_terms, [callback.base_ctype.lower()], idx) + add_index_terms(index_terms, utils.index_identifier(callback.name, stemmer), idx) + add_index_terms(index_terms, utils.index_description(cb_desc, stemmer), idx) + + +def _gen_classes(config, stemmer, index, repository, symbols): + namespace = repository.namespace + + index_symbols = index["symbols"] + index_terms = index["terms"] + + for cls in symbols: + if config.is_hidden(cls.name): + log.debug(f"Skipping hidden type {cls.name}") + continue + idx = len(index_symbols) + if cls.doc is not None: + cls_desc = cls.doc.content + else: + cls_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "class", + "name": cls.name, + "ctype": cls.base_ctype, + "summary": utils.preprocess_docs(cls_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [cls.base_ctype.lower()], idx) + add_index_terms(index_terms, utils.index_identifier(cls.name, stemmer), idx) + add_index_terms(index_terms, utils.index_description(cls_desc, stemmer), idx) + + for ctor in cls.constructors: + ctor_idx = len(index_symbols) + if ctor.doc is not None: + ctor_desc = ctor.doc.content + else: + ctor_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "ctor", + "name": ctor.name, + "type_name": cls.name, + "ident": ctor.identifier, + "summary": utils.preprocess_docs(ctor_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [ctor.identifier], ctor_idx) + add_index_terms(index_terms, utils.index_symbol(ctor.name, stemmer), ctor_idx) + add_index_terms(index_terms, utils.index_description(ctor_desc, stemmer), ctor_idx) + + for method in cls.methods: + method_idx = len(index_symbols) + if method.doc is not None: + method_desc = method.doc.content + else: + method_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "method", + "name": method.name, + "type_name": cls.name, + "ident": method.identifier, + "summary": utils.preprocess_docs(method_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [method.identifier], method_idx) + add_index_terms(index_terms, utils.index_symbol(method.name, stemmer), method_idx) + add_index_terms(index_terms, utils.index_description(method_desc, stemmer), method_idx) + + for func in cls.functions: + func_idx = len(index_symbols) + if func.doc is not None: + func_desc = func.doc.content + else: + func_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "type_func", + "name": func.name, + "type_name": cls.name, + "ident": func.identifier, + "summary": utils.preprocess_docs(func_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [func.identifier], func_idx) + add_index_terms(index_terms, utils.index_symbol(func.name, stemmer), func_idx) + add_index_terms(index_terms, utils.index_description(func_desc, stemmer), func_idx) + + for prop_name, prop in cls.properties.items(): + if config.is_hidden(cls.name, 'property', prop_name): + log.debug(f"Skipping hidden property {cls.name}.{prop_name}") + continue + prop_idx = len(index_symbols) + if prop.doc is not None: + prop_desc = prop.doc.content + else: + prop_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "property", + "name": prop.name, + "type_name": cls.name, + "summary": utils.preprocess_docs(prop_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, utils.index_symbol(prop.name, stemmer), prop_idx) + add_index_terms(index_terms, utils.index_description(prop_desc, stemmer), prop_idx) + + for signal_name, signal in cls.signals.items(): + if config.is_hidden(cls.name, 'signal', signal_name): + log.debug(f"Skipping hidden signal {cls.name}.{signal_name}") + continue + signal_idx = len(index_symbols) + if signal.doc is not None: + signal_desc = signal.doc.content + else: + signal_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "signal", + "name": signal.name, + "type_name": cls.name, + "summary": utils.preprocess_docs(signal_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, utils.index_symbol(signal.name, stemmer), signal_idx) + add_index_terms(index_terms, utils.index_description(signal_desc, stemmer), signal_idx) + + for vfunc in cls.virtual_methods: + vfunc_idx = len(index_symbols) + if vfunc.doc is not None: + vfunc_desc = vfunc.doc.content + else: + vfunc_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "vfunc", + "name": vfunc.name, + "type_name": cls.name, + "summary": utils.preprocess_docs(vfunc_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, utils.index_symbol(vfunc.name, stemmer), vfunc_idx) + add_index_terms(index_terms, utils.index_description(vfunc_desc, stemmer), vfunc_idx) + + if cls.type_struct is not None: + cls_struct = namespace.find_record(cls.type_struct) + for cls_method in cls_struct.methods: + cls_method_idx = len(index_symbols) + if cls_method.doc is not None: + cls_method_desc = cls_method.doc.content + else: + cls_method_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "class_method", + "name": cls_method.name, + "type_name": cls_struct.name, + "struct_for": cls_struct.struct_for, + "ident": cls_method.identifier, + "summary": utils.preprocess_docs(cls_method_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [cls_method.identifier], cls_method_idx) + add_index_terms(index_terms, utils.index_symbol(cls_method.name, stemmer), cls_method_idx) + add_index_terms(index_terms, utils.index_description(cls_method_desc, stemmer), cls_method_idx) + + +def _gen_constants(config, stemmer, index, repository, symbols): + index_symbols = index["symbols"] + index_terms = index["terms"] + + for const in symbols: + if config.is_hidden(const.name): + log.debug(f"Skipping hidden const {const.name}") + continue + idx = len(index_symbols) + if const.doc is not None: + const_desc = const.doc.content + else: + const_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "constant", + "name": const.name, + "ident": const.ctype, + "summary": utils.preprocess_docs(const_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [const.ctype.lower()], idx) + add_index_terms(index_terms, utils.index_symbol(const.name, stemmer), idx) + add_index_terms(index_terms, utils.index_description(const_desc, stemmer), idx) + + +def _gen_domains(config, stemmer, index, repository, symbols): + index_symbols = index["symbols"] + index_terms = index["terms"] + + for domain in symbols: + if config.is_hidden(domain.name): + log.debug(f"Skipping hidden type {domain.name}") + continue + idx = len(index_symbols) + if domain.doc is not None: + domain_desc = domain.doc.content + else: + domain_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "domain", + "name": domain.name, + "ctype": domain.base_ctype, + "summary": utils.preprocess_docs(domain_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [domain.base_ctype.lower()], idx) + add_index_terms(index_terms, utils.index_identifier(domain.name, stemmer), idx) + add_index_terms(index_terms, utils.index_description(domain_desc, stemmer), idx) + + for member in domain.members: + add_index_terms(index_terms, [member.name], idx) + if member.doc is not None: + add_index_terms(index_terms, utils.index_description(member.doc.content, stemmer), idx) + + for func in domain.functions: + func_idx = len(index_symbols) + if func.doc is not None: + func_desc = func.doc.content + else: + func_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "type_func", + "name": func.name, + "type_name": domain.name, + "ident": func.identifier, + "summary": utils.preprocess_docs(func_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [func.identifier], func_idx) + add_index_terms(index_terms, utils.index_symbol(func.name, stemmer), func_idx) + add_index_terms(index_terms, utils.index_description(func_desc, stemmer), func_idx) + + +def _gen_enums(config, stemmer, index, repository, symbols): + index_symbols = index["symbols"] + index_terms = index["terms"] + + for enum in symbols: + if config.is_hidden(enum.name): + log.debug(f"Skipping hidden type {enum.name}") + continue + idx = len(index_symbols) + if enum.doc is not None: + enum_desc = enum.doc.content + else: + enum_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "enum", + "name": enum.name, + "ctype": enum.base_ctype, + "summary": utils.preprocess_docs(enum_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [enum.base_ctype.lower()], idx) + add_index_terms(index_terms, utils.index_identifier(enum.name, stemmer), idx) + add_index_terms(index_terms, utils.index_description(enum_desc, stemmer), idx) + + for member in enum.members: + add_index_terms(index_terms, [member.name], idx) + if member.doc is not None: + add_index_terms(index_terms, utils.index_description(member.doc.content, stemmer), idx) + + for func in enum.functions: + func_idx = len(index_symbols) + if func.doc is not None: + func_desc = func.doc.content + else: + func_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "type_func", + "name": func.name, + "type_name": enum.name, + "ident": func.identifier, + "summary": utils.preprocess_docs(func_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [func.identifier], func_idx) + add_index_terms(index_terms, utils.index_symbol(func.name, stemmer), func_idx) + add_index_terms(index_terms, utils.index_description(func_desc, stemmer), func_idx) + + +def _gen_functions(config, stemmer, index, repository, symbols): + index_symbols = index["symbols"] + index_terms = index["terms"] + + for func in symbols: + if config.is_hidden(func.name): + log.debug(f"Skipping hidden function {func.name}") + continue + idx = len(index_symbols) + if func.doc is not None: + func_desc = func.doc.content + else: + func_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "function", + "name": func.name, + "ident": func.identifier, + "summary": utils.preprocess_docs(func_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [func.identifier], idx) + add_index_terms(index_terms, utils.index_symbol(func.name, stemmer), idx) + add_index_terms(index_terms, utils.index_description(func_desc, stemmer), idx) + + +def _gen_function_macros(config, stemmer, index, repository, symbols): + index_symbols = index["symbols"] + index_terms = index["terms"] + + for func in symbols: + if config.is_hidden(func.name): + log.debug(f"Skipping hidden macro {func.name}") + continue + idx = len(index_symbols) + if func.doc is not None: + func_desc = func.doc.content + else: + func_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "function_macro", + "name": func.name, + "ident": func.identifier, + "summary": utils.preprocess_docs(func_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [func.identifier], idx) + add_index_terms(index_terms, utils.index_symbol(func.name, stemmer), idx) + add_index_terms(index_terms, utils.index_description(func_desc, stemmer), idx) + + +def _gen_interfaces(config, stemmer, index, repository, symbols): + index_symbols = index["symbols"] + index_terms = index["terms"] + + for iface in symbols: + if config.is_hidden(iface.name): + log.debug(f"Skipping hidden type {iface.name}") + continue + idx = len(index_symbols) + if iface.doc is not None: + iface_desc = iface.doc.content + else: + iface_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "interface", + "name": iface.name, + "ctype": iface.base_ctype, + "summary": utils.preprocess_docs(iface_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [iface.base_ctype.lower()], idx) + add_index_terms(index_terms, utils.index_identifier(iface.name, stemmer), idx) + add_index_terms(index_terms, utils.index_description(iface_desc, stemmer), idx) + + for method in iface.methods: + method_idx = len(index_symbols) + if method.doc is not None: + method_desc = method.doc.content + else: + method_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "method", + "name": method.name, + "type_name": iface.name, + "ident": method.identifier, + "summary": utils.preprocess_docs(method_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [method.identifier], method_idx) + add_index_terms(index_terms, utils.index_symbol(method.name, stemmer), method_idx) + add_index_terms(index_terms, utils.index_description(method_desc, stemmer), method_idx) + + for func in iface.functions: + func_idx = len(index_symbols) + if func.doc is not None: + func_desc = func.doc.content + else: + func_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "type_func", + "name": func.name, + "type_name": iface.name, + "ident": func.identifier, + "summary": utils.preprocess_docs(func_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [func.identifier], func_idx) + add_index_terms(index_terms, utils.index_symbol(func.name, stemmer), func_idx) + add_index_terms(index_terms, utils.index_description(func_desc, stemmer), func_idx) + + for prop_name, prop in iface.properties.items(): + if config.is_hidden(iface.name, 'property', prop_name): + log.debug(f"Skipping hidden property {iface.name}.{prop_name}") + continue + prop_idx = len(index_symbols) + if prop.doc is not None: + prop_desc = prop.doc.content + else: + prop_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "property", + "name": prop.name, + "type_name": iface.name, + "summary": utils.preprocess_docs(prop_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, utils.index_symbol(prop.name, stemmer), prop_idx) + add_index_terms(index_terms, utils.index_description(prop_desc, stemmer), prop_idx) + + for signal_name, signal in iface.signals.items(): + if config.is_hidden(iface.name, 'signal', signal_name): + log.debug(f"Skipping hidden signal {iface.name}.{signal_name}") + continue + signal_idx = len(index_symbols) + if signal.doc is not None: + signal_desc = signal.doc.content + else: + signal_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "signal", + "name": signal.name, + "type_name": iface.name, + "summary": utils.preprocess_docs(signal_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, utils.index_symbol(signal.name, stemmer), signal_idx) + add_index_terms(index_terms, utils.index_description(signal_desc, stemmer), signal_idx) + + for vfunc in iface.virtual_methods: + vfunc_idx = len(index_symbols) + if vfunc.doc is not None: + vfunc_desc = vfunc.doc.content + else: + vfunc_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "vfunc", + "name": vfunc.name, + "type_name": iface.name, + "summary": utils.preprocess_docs(vfunc_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, utils.index_symbol(vfunc.name, stemmer), vfunc_idx) + add_index_terms(index_terms, utils.index_description(vfunc_desc, stemmer), vfunc_idx) + + +def _gen_records(config, stemmer, index, repository, symbols): + index_symbols = index["symbols"] + index_terms = index["terms"] + + for record in symbols: + if config.is_hidden(record.name): + log.debug(f"Skipping hidden type {record.name}") + continue + idx = len(index_symbols) + if record.doc is not None: + desc = record.doc.content + else: + desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "record", + "name": record.name, + "ctype": record.base_ctype, + "summary": utils.preprocess_docs(desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [record.base_ctype.lower()], idx) + add_index_terms(index_terms, utils.index_identifier(record.name, stemmer), idx) + add_index_terms(index_terms, utils.index_description(desc, stemmer), idx) + + for ctor in record.constructors: + ctor_idx = len(index_symbols) + if ctor.doc is not None: + ctor_desc = ctor.doc.content + else: + ctor_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "ctor", + "name": ctor.name, + "type_name": record.name, + "ident": ctor.identifier, + "summary": utils.preprocess_docs(ctor_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [ctor.identifier], ctor_idx) + add_index_terms(index_terms, utils.index_symbol(ctor.name, stemmer), ctor_idx) + add_index_terms(index_terms, utils.index_description(ctor_desc, stemmer), ctor_idx) + + for method in record.methods: + method_idx = len(index_symbols) + if method.doc is not None: + method_desc = method.doc.content + else: + method_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "method", + "name": method.name, + "type_name": record.name, + "ident": method.identifier, + "summary": utils.preprocess_docs(method_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [method.identifier], method_idx) + add_index_terms(index_terms, utils.index_symbol(method.name, stemmer), method_idx) + add_index_terms(index_terms, utils.index_description(method_desc, stemmer), method_idx) + + for func in record.functions: + func_idx = len(index_symbols) + if func.doc is not None: + func_desc = func.doc.content + else: + func_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "type_func", + "name": func.name, + "type_name": record.name, + "ident": func.identifier, + "summary": utils.preprocess_docs(func_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [func.identifier], func_idx) + add_index_terms(index_terms, utils.index_symbol(func.name, stemmer), func_idx) + add_index_terms(index_terms, utils.index_description(func_desc, stemmer), func_idx) + + +def _gen_unions(config, stemmer, index, repository, symbols): + index_symbols = index["symbols"] + index_terms = index["terms"] + + for union in symbols: + if config.is_hidden(union.name): + log.debug(f"Skipping hidden type {union.name}") + continue + idx = len(index_symbols) + if union.doc is not None: + desc = union.doc.content + else: + desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "union", + "name": union.name, + "ctype": union.base_ctype, + "summary": utils.preprocess_docs(desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [union.base_ctype.lower()], idx) + add_index_terms(index_terms, utils.index_identifier(union.name, stemmer), idx) + add_index_terms(index_terms, utils.index_description(desc, stemmer), idx) + + for ctor in union.constructors: + ctor_idx = len(index_symbols) + if ctor.doc is not None: + ctor_desc = ctor.doc.content + else: + ctor_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "ctor", + "name": ctor.name, + "type_name": union.name, + "ident": ctor.identifier, + "summary": utils.preprocess_docs(ctor_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [ctor.identifier], ctor_idx) + add_index_terms(index_terms, utils.index_symbol(ctor.name, stemmer), ctor_idx) + add_index_terms(index_terms, utils.index_description(ctor_desc, stemmer), ctor_idx) + + for method in union.methods: + method_idx = len(index_symbols) + if method.doc is not None: + method_desc = method.doc.content + else: + method_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "method", + "name": method.name, + "type_name": union.name, + "ident": method.identifier, + "summary": utils.preprocess_docs(method_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [method.identifier], method_idx) + add_index_terms(index_terms, utils.index_symbol(method.name, stemmer), method_idx) + add_index_terms(index_terms, utils.index_description(method_desc, stemmer), method_idx) + + for func in union.functions: + func_idx = len(index_symbols) + if func.doc is not None: + func_desc = func.doc.content + else: + func_desc = MISSING_DESCRIPTION + index_symbols.append({ + "type": "type_func", + "name": func.name, + "type_name": union.name, + "ident": func.identifier, + "summary": utils.preprocess_docs(func_desc, repository.namespace, summary=True, plain=True), + }) + add_index_terms(index_terms, [func.identifier], func_idx) + add_index_terms(index_terms, utils.index_symbol(func.name, stemmer), func_idx) + add_index_terms(index_terms, utils.index_description(func_desc, stemmer), func_idx) + + - def gen_indices(config, repository, content_dir, output_dir): ++def _gen_content_files(config, stemmer, index, repository, content_dirs): ++ index_symbols = index["symbols"] ++ index_terms = index["terms"] ++ ++ for file_name in config.content_files: ++ src_file = utils.find_extra_content_file(content_dirs, file_name) ++ ++ src_data = "" ++ with open(src_file, encoding='utf-8') as infile: ++ source = [] ++ header = True ++ title = None ++ for line in infile: ++ if header: ++ if line.startswith("Title: "): ++ title = line.replace("Title: ", "").strip() ++ if line == "\n": ++ header = False ++ ++ if not header: ++ source.append(line) ++ src_data = "".join(source) ++ ++ if title is None: ++ title = f"Untitled document '{file_name}'" ++ ++ index_symbols.append({ ++ "type": "content", ++ "name": title, ++ "href": file_name.replace(".md", ".html"), ++ "summary": utils.preprocess_docs(src_data, repository.namespace, summary=True, plain=True), ++ }) ++ ++ content_idx = len(index_symbols) ++ add_index_terms(index_terms, utils.index_description(src_data, stemmer), content_idx) ++ ++ ++def gen_indices(config, repository, content_dirs, output_dir): + namespace = repository.namespace + + symbols = { + "aliases": sorted(namespace.get_aliases(), key=lambda alias: alias.name.lower()), + "bitfields": sorted(namespace.get_bitfields(), key=lambda bitfield: bitfield.name.lower()), + "callbacks": sorted(namespace.get_callbacks(), key=lambda callback: callback.name.lower()), + "classes": sorted(namespace.get_classes(), key=lambda cls: cls.name.lower()), + "constants": sorted(namespace.get_constants(), key=lambda const: const.name.lower()), + "domains": sorted(namespace.get_error_domains(), key=lambda domain: domain.name.lower()), + "enums": sorted(namespace.get_enumerations(), key=lambda enum: enum.name.lower()), + "functions": sorted(namespace.get_functions(), key=lambda func: func.name.lower()), + "function_macros": sorted(namespace.get_effective_function_macros(), key=lambda func: func.name.lower()), + "interfaces": sorted(namespace.get_interfaces(), key=lambda interface: interface.name.lower()), + "structs": sorted(namespace.get_effective_records(), key=lambda record: record.name.lower()), + "unions": sorted(namespace.get_unions(), key=lambda union: union.name.lower()), + } + + all_indices = { + "aliases": _gen_aliases, + "bitfields": _gen_bitfields, + "callbacks": _gen_callbacks, + "classes": _gen_classes, + "constants": _gen_constants, + "domains": _gen_domains, + "enums": _gen_enums, + "functions": _gen_functions, + "function_macros": _gen_function_macros, + "interfaces": _gen_interfaces, + "structs": _gen_records, + "unions": _gen_unions, + } + + index = { + "meta": { + "ns": namespace.name, + "version": namespace.version, + "generator": "gi-docgen", + "generator-version": core.version, + }, + "symbols": [], + "terms": {}, + } + + stemmer = porter.PorterStemmer() + + # Each section is isolated, so we run it into a thread pool + for section in all_indices: + generator = all_indices.get(section, None) + if generator is None: + log.error(f"No generator for section {section}") + continue + + s = symbols.get(section, None) + if s is None: + log.debug(f"No symbols for section {section}") + continue + + log.debug(f"Generating symbols for section {section}") + generator(config, stemmer, index, repository, s) + ++ _gen_content_files(config, stemmer, index, repository, content_dirs) ++ + # Ensure iteration order is reproducible by sorting symbols by type/name, + # and terms by key. This has no overhead since values are not copied. + index["symbols"].sort(key=lambda s: (s["type"], s["name"])) + index["terms"] = dict(sorted(index["terms"].items())) + + data = json.dumps(index, separators=(',', ':')) + index_file = os.path.join(output_dir, "index.json") + log.info(f"Creating index file for {namespace.name}-{namespace.version}: {index_file}") + with open(index_file, "w") as out: + out.write(data) + + +def add_args(parser): + parser.add_argument("--add-include-path", action="append", dest="include_paths", default=[], + help="include paths for other GIR files") + parser.add_argument("-C", "--config", metavar="FILE", help="the configuration file") - parser.add_argument("--content-dir", default=None, help="the base directory with the extra content") ++ parser.add_argument("--content-dir", action="append", dest="content_dirs", default=[], ++ help="the base directories with the extra content") + parser.add_argument("--dry-run", action="store_true", help="parses the GIR file without generating files") + parser.add_argument("--output-dir", default=None, help="the output directory for the index files") + parser.add_argument("infile", metavar="GIRFILE", type=argparse.FileType('r', encoding='UTF-8'), + default=sys.stdin, help="the GIR file to parse") + + +def run(options): + log.info(f"Loading config file: {options.config}") + + conf = config.GIDocConfig(options.config) + + output_dir = options.output_dir or os.getcwd() - content_dir = options.content_dir or os.getcwd() + log.info(f"Output directory: {output_dir}") + ++ content_dirs = options.content_dirs ++ if content_dirs == []: ++ content_dirs = [os.getcwd()] ++ + paths = [] + paths.extend(options.include_paths) + paths.extend(utils.default_search_paths()) + log.debug(f"Search paths: {paths}") + + log.info("Parsing GIR file") + parser = gir.GirParser(search_paths=paths) + parser.parse(options.infile) + + if not options.dry_run: + log.checkpoint() - gen_indices(conf, parser.get_repository(), content_dir, output_dir) ++ gen_indices(conf, parser.get_repository(), content_dirs, output_dir) + + return 0 diff --cc subprojects/gi-docgen/gidocgen/gidocmain.py index 679efa61f5,0000000000..a3c97f2eda mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/gidocmain.py +++ b/subprojects/gi-docgen/gidocgen/gidocmain.py @@@ -1,125 -1,0 +1,129 @@@ +# SPDX-FileCopyrightText: 2020 GNOME Foundation +# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +import argparse +import shutil +import sys +import traceback + +from . import core, log - from . import gdindex, gdgenerate, gdgenindices, gdgendeps, gdsearch ++from . import gdindex, gdgenerate, gdgenindices, gdgendeps, gdsearch, gdcheck + + +class GIDocGenApp: + """ + The main GIDocGen application, working as a multiplexer for different + commands. + """ + def __init__(self): + self.term_width = shutil.get_terminal_size().columns + self.formatter = lambda prog: argparse.HelpFormatter(prog, max_help_position=int(self.term_width / 2), width=self.term_width) + + self.quiet = False + self.commands = {} + self.parser = argparse.ArgumentParser(prog='gi-docgen', formatter_class=self.formatter) + + self.subparser = self.parser.add_subparsers(title='Commands', + description='If no command is specified, default to help') + + self.add_command('help', + add_args_func=self.add_help_args, + run_func=self.run_help_cmd, + help_msg='Show the help for gi-docgen or a sub-command') + self.add_command('index', + add_args_func=gdindex.add_args, + run_func=gdindex.run, + help_msg=gdindex.HELP_MSG) + self.add_command('generate', + add_args_func=gdgenerate.add_args, + run_func=gdgenerate.run, + help_msg=gdgenerate.HELP_MSG) + self.add_command('gen-index', + add_args_func=gdgenindices.add_args, + run_func=gdgenindices.run, + help_msg=gdgenindices.HELP_MSG) + self.add_command('gen-deps', + add_args_func=gdgendeps.add_args, + run_func=gdgendeps.run, + help_msg=gdgendeps.HELP_MSG) + self.add_command('search', + add_args_func=gdsearch.add_args, + run_func=gdsearch.run, + help_msg=gdsearch.HELP_MSG) ++ self.add_command('check', ++ add_args_func=gdcheck.add_args, ++ run_func=gdcheck.run, ++ help_msg=gdcheck.HELP_MSG) + + def run(self, args): + """ + Run the main application. + """ + known_commands = list(self.commands.keys()) + ['-h', '--help'] + if not args or args[0] not in known_commands: + args = ['help'] + args + + options = self.parser.parse_args(args) + + # Set up the logging system + log.set_quiet(options.quiet) + log.set_fatal_warnings(options.fatal_warnings) + log.set_log_epoch() + + try: + res = options.run_func(options) + if 'help' not in args: + report_res = log.report() + else: + report_res = 0 + if res == 0: + return report_res + return res + + except Exception: + traceback.print_exc() + return 1 + + def add_command(self, name, add_args_func, run_func, help_msg, aliases=[]): + """ + Add a command to the application. + + @name (str): the name of the command + @add_args_func (callable): a function to be called to add the arguments + @run_func (callable): a function to be called when running the command + @help_msg (str): short help message for the command + @aliases (array): a list of aliases for the command + """ + p = self.subparser.add_parser(name, help=help_msg, aliases=aliases, formatter_class=self.formatter) + + # Add shared commands + p.add_argument("-q", "--quiet", action="store_true", help="suppress messages except warnings") + p.add_argument("--fatal-warnings", action="store_true", help="whether warnings are fatal") + + if add_args_func: + add_args_func(p) + p.set_defaults(run_func=run_func) + for i in [name] + aliases: + self.commands[i] = p + + def add_help_args(self, parser): + parser.add_argument("-v", "--version", action="store_true", help="show the version of gi-docgen") + parser.add_argument('command', nargs='?') + + def run_help_cmd(self, options): + if options.version: + print(core.version) + elif options.command: + known_commands = list(self.commands.keys()) + if options.command not in known_commands: + log.error(f'Unknown command {options.command}.') + return 1 + self.commands[options.command].print_help() + else: + self.parser.print_help() + return 0 + + +def main(): + """The entry point expected by setuptools""" + return GIDocGenApp().run(sys.argv[1:]) diff --cc subprojects/gi-docgen/gidocgen/gir/ast.py index e3a86adc5b,0000000000..8a7294a102 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/gir/ast.py +++ b/subprojects/gi-docgen/gidocgen/gir/ast.py @@@ -1,1172 -1,0 +1,1272 @@@ +# SPDX-FileCopyrightText: 2020 GNOME Foundation +# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +import typing as T + +from .. import log + + +class Doc: + """A documentation node, pointing to the source code""" + def __init__(self, content: str, filename: str, line: int, version: str = None, stability: str = None): + self.content = content + self.filename = filename + self.line = line + self.version = version + self.stability = stability + + def __str__(self): + return self.content + + +class SourcePosition: + """A location inside the source code""" + def __init__(self, filename: str, line: int): + self.filename = filename + self.line = line + + def __str__(self): + return f'{self.filename}:{self.line}' + + +class Attribute: + """A user-defined annotation""" + def __init__(self, name: str, value: T.Optional[str]): + self.name = name + self.value = value + + +class CInclude: + """A C include header""" + def __init__(self, name: str): + self.name = name + + +class Include: + """A GIR include""" + def __init__(self, name: str, version: str = None): + self.name = name + self.version = version + + def __str__(self): + if self.version is not None: + return f"{self.name}-{self.version}" + return f"{self.name}" + + def girfile(self) -> str: + if self.version is not None: + return f"{self.name}-{self.version}.gir" + return f"{self.name}.gir" + + +class Package: + """Pkg-config containing the library""" + def __init__(self, name: str): + self.name = name + + +class Info: + """Base information for most types""" + def __init__(self, introspectable: bool = True, deprecated: T.Optional[str] = None, + deprecated_version: T.Optional[str] = None, version: str = None, + stability: str = None): + self.introspectable = introspectable + self.deprecated_msg = deprecated + self.deprecated_version = deprecated_version + self.version = version + self.stability = stability + self.attributes: T.Mapping[str, T.Optional[str]] = {} + self.doc: T.Optional[Doc] = None + self.source_position: T.Optional[SourcePosition] = None + + def add_attribute(self, name: str, value: T.Optional[str] = None) -> None: + self.attributes[name] = value + + +class GIRElement: + """Base type for elements inside the GIR""" + def __init__(self, name: T.Optional[str] = None, namespace: T.Optional[str] = None): + self.name = name + self.namespace = namespace - if self.namespace is not None: ++ if self.namespace is None: + if self.name is not None and '.' in self.name: + self.namespace = self.name.split('.')[0] + self.info = Info() + + def set_introspectable(self, introspectable: bool) -> None: + """Set whether the symbol is introspectable""" + self.info.introspectable = introspectable + + @property + def introspectable(self): + return self.info.introspectable + + def set_version(self, version: str) -> None: + """Set the version of the symbol""" + self.info.version = version + + def set_stability(self, stability: str) -> None: + """Set the stability of the symbol""" + self.info.stability = stability + + @property + def stability(self): + return self.info.stability + + def set_doc(self, doc: Doc) -> None: + """Set the documentation for the element""" + self.info.doc = doc + + @property + def doc(self): + return self.info.doc + + def set_source_position(self, pos: SourcePosition) -> None: + """Set the position in the source code for the element""" + self.info.source_position = pos + + @property + def source_position(self) -> T.Optional[T.Tuple[str, int]]: + if self.info.source_position is None: + return None + return self.info.source_position.filename, self.info.source_position.line + + def set_deprecated(self, doc: T.Optional[str] = None, since_version: T.Optional[str] = None) -> None: + """Set the deprecation annotations for the element""" + self.info.deprecated_msg = doc + self.info.deprecated_version = since_version + + def set_attributes(self, attrs: T.Mapping[str, T.Optional[str]]) -> None: + """Add an annotation to the symbol""" + for name, value in attrs.items(): + self.info.add_attribute(name, value) + + @property + def attributes(self) -> T.Mapping[str, T.Optional[str]]: + return self.info.attributes + + @property + def available_since(self) -> T.Optional[str]: + return self.info.version + + @property + def deprecated_since(self) -> T.Optional[T.Tuple[str, str]]: + if not self.info.deprecated_msg: + return None + version = self.info.deprecated_version + message = self.info.deprecated_msg + if message is None: + message = "Please do not use it in newly written code" + return (version, message) + + +class Type(GIRElement): + """Base class for all Type nodes""" - def __init__(self, name: str, ctype: T.Optional[str] = None, namespace: T.Optional[str] = None): ++ def __init__(self, name: str, ctype: T.Optional[str] = None, namespace: T.Optional[str] = None, is_fundamental: bool = False): + super().__init__(name=name, namespace=namespace) + self.ctype = ctype ++ self.is_fundamental = is_fundamental + + def __eq__(self, other): + if isinstance(other, Type): + if self.namespace is not None: - return self.namespace == other.namespace and self.name == self.name ++ return self.namespace == other.namespace and self.name == other.name + elif self.ctype is not None: + return self.name == other.name and self.ctype == other.ctype + else: + return self.name == other.name + elif isinstance(other, str): + return self.name == other + else: + return False + + def __cmp__(self, other): + if self.ctype is not None: + return self.name == other.name and self.ctype == other.ctype + return self.name == other.name + + def __repr__(self): + return f"Type({self.fqtn}, {self.ctype})" + + @property + def resolved(self): + return self.ctype is not None + + @property + def base_ctype(self): + if self.ctype is None: + return None + return self.ctype.replace('*', '') + + @property + def fqtn(self): - if '.' in self.name: ++ if self.is_fundamental: ++ return self.name ++ elif '.' in self.name: + return self.name + elif self.namespace is not None: + return f"{self.namespace}.{self.name}" + else: + return None + + +class ArrayType(GIRElement): + """Base class for Array nodes""" + def __init__(self, name: str, value_type: Type, ctype: str = None, zero_terminated: bool = False, + fixed_size: int = -1, length: int = -1): + super().__init__(name) + self.ctype = ctype + self.zero_terminated = zero_terminated + self.fixed_size = fixed_size + self.length = length + self.value_type = value_type ++ self.is_fundamental = False + + +class ListType(GIRElement): + """Type class for List nodes""" + def __init__(self, name: str, value_type: Type, ctype: str = None): + super().__init__(name) + self.ctype = ctype + self.value_type = value_type ++ self.is_fundamental = False + + +class MapType(GIRElement): + """Type class for Map nodes""" + def __init__(self, name: str, key_type: Type, value_type: Type, ctype: str = None): + super().__init__(name) + self.ctype = ctype + self.key_type = key_type + self.value_type = value_type ++ self.is_fundamental = False + + +class GType: + """Base class for GType information""" + def __init__(self, type_name: str, get_type: str, type_struct: T.Optional[str] = None): + self.type_name = type_name + self.get_type = get_type + self.type_struct = type_struct + + +class VoidType(Type): + def __init__(self): + super().__init__(name='none', ctype='void') + + def __str__(self): + return "void" + + +class VarArgs(Type): + def __init__(self): + super().__init__(name='none', ctype='') + + def __str__(self): + return "..." + + +class Alias(Type): + """Alias to a Type""" + def __init__(self, name: str, namespace: str, ctype: str, target: Type): + super().__init__(name=name, ctype=ctype, namespace=namespace) + self.target = target + + +class Constant(Type): + """A constant""" + def __init__(self, name: str, namespace: str, ctype: str, target: Type, value: str): + super().__init__(name=name, ctype=ctype, namespace=namespace) + self.target = target + self.value = value + + +class Parameter(GIRElement): + """A callable parameter""" + def __init__(self, name: str, direction: str, transfer: str, target: Type = None, caller_allocates: bool = False, + optional: bool = False, nullable: bool = False, closure: int = -1, destroy: int = -1, + scope: str = None): + super().__init__(name) + self.direction = direction + self.transfer = transfer + self.caller_allocates = caller_allocates + self.optional = optional + self.nullable = nullable + self.scope = scope + self.closure = closure + self.destroy = destroy + if target is None: + self.target: Type = VoidType() + else: + self.target = target + + +class ReturnValue(GIRElement): + """A callable's return value""" + def __init__(self, transfer: str, target: Type, nullable: bool = False, closure: int = -1, destroy: int = -1, scope: str = None): + super().__init__() + self.transfer = transfer + self.nullable = nullable + self.scope = scope + self.closure = closure + self.destroy = destroy + if target is None: + self.target: Type = VoidType() + else: + self.target = target + + +class Callable(GIRElement): + """A callable symbol: function, method, function-macro, ...""" + def __init__(self, name: str, namespace: T.Optional[str], identifier: T.Optional[str], throws: bool = False): + super().__init__(name=name, namespace=namespace) + self.identifier = identifier + self.parameters: T.List[Parameter] = [] + self.return_value: T.Optional[ReturnValue] = None + self.throws: bool = throws + self.moved_to: T.Optional[str] = None + self.shadows: T.Optional[str] = None + self.shadowed_by: T.Optional[str] = None + + def add_parameter(self, param: Parameter) -> None: + self.parameters.append(param) + + def set_parameters(self, params: T.List[Parameter]) -> None: + self.parameters.extend(params) + + def set_return_value(self, res: ReturnValue) -> None: + self.return_value = res + + def set_shadows(self, func: str) -> None: + self.shadows = func + + def set_shadowed_by(self, func: str) -> None: + self.shadowed_by = func + + def set_moved_to(self, func: str) -> None: + self.moved_to = func + + def __contains__(self, param): + if isinstance(param, str): + for p in self.parameters: + if p.name == param: + return True + elif isinstance(param, Parameter): + return param in self.parameters + elif isinstance(param, ReturnValue): + return param == self.return_value + return False + + +class FunctionMacro(Callable): + def __init__(self, name: str, namespace: T.Optional[str], identifier: str): + super().__init__(name, namespace, identifier) + + +class Function(Callable): + def __init__(self, name: str, namespace: T.Optional[str], identifier: str, throws: bool = False): + super().__init__(name, namespace, identifier, throws) + + +class Method(Callable): - def __init__(self, name: str, identifier: str, instance_param: Parameter, throws: bool = False): ++ def __init__(self, name: str, identifier: str, instance_param: Parameter, throws: bool = False, ++ set_property: T.Optional[str] = None, get_property: T.Optional[str] = None): + super().__init__(name, None, identifier, throws) + self.instance_param = instance_param ++ self.set_property = set_property ++ self.get_property = get_property + + def __contains__(self, param): + if isinstance(param, Parameter) and param == self.instance_param: + return True + return super().__contains__(self, param) + + +class VirtualMethod(Callable): + def __init__(self, name: str, identifier: str, invoker: str, instance_param: Parameter, throws: bool = False): + super().__init__(name, None, identifier, throws) + self.instance_param = instance_param + self.invoker = invoker + + def __contains__(self, param): + if isinstance(param, Parameter) and param == self.instance_param: + return True + return super().__contains__(self, param) + + +class Callback(Callable): + def __init__(self, name: str, namespace: str, ctype: T.Optional[str], throws: bool = False): + super().__init__(name=name, namespace=namespace, identifier=None, throws=throws) + self.ctype = ctype ++ self.is_fundamental = False + + @property + def base_ctype(self): + if self.ctype is None: + return None + return self.ctype.replace('*', '') + + +class Member(GIRElement): + """A member in an enumeration, error domain, or bitfield""" + def __init__(self, name: str, value: str, identifier: str, nick: str): + super().__init__(name) + self.value = value + self.identifier = identifier + self.nick = nick + + +class Enumeration(Type): + """An enumeration type""" + def __init__(self, name: str, namespace: str, ctype: str, gtype: T.Optional[GType]): + super().__init__(name=name, ctype=ctype, namespace=namespace) + self.gtype = gtype + self.members: T.List[Member] = [] + self.functions: T.List[Function] = [] + + def add_member(self, member: Member) -> None: + self.members.append(member) + + def add_function(self, function: Function) -> None: + self.functions.append(function) + + def set_members(self, members: T.List[Member]) -> None: + self.members.extend(members) + + def set_functions(self, functions: T.List[Function]) -> None: + self.functions.extend(functions) + + def __contains__(self, member): + if isinstance(member, Member): + return member in self.members + return False + + def __iter__(self): + for member in self.members: + yield member + + +class BitField(Enumeration): + """An enumeration type of bit masks""" + def __init__(self, name: str, namespace: str, ctype: str, gtype: T.Optional[GType]): + super().__init__(name, namespace, ctype, gtype) + + +class ErrorDomain(Enumeration): + """An error domain for GError""" + def __init__(self, name: str, namespace: str, ctype: str, gtype: T.Optional[GType], domain: str): + super().__init__(name, namespace, ctype, gtype) + self.domain = domain + + +class Property(GIRElement): + def __init__(self, name: str, transfer: str, target: Type, writable: bool = True, readable: bool = True, construct: bool = False, - construct_only: bool = False): ++ construct_only: bool = False, setter: T.Optional[str] = None, getter: T.Optional[str] = None): + super().__init__(name) + self.transfer = transfer + self.writable = writable + self.readable = readable + self.construct = construct + self.construct_only = construct_only + self.target = target ++ self.setter = setter ++ self.getter = getter + + +class Signal(GIRElement): + def __init__(self, name: str, detailed: bool, when: str, action: bool = False, no_hooks: bool = False, no_recurse: bool = False): + super().__init__(name) + self.detailed = detailed + self.when = when + self.action = action + self.no_hooks = no_hooks + self.no_recurse = no_recurse + self.parameters: T.List[Parameter] = [] + self.return_value: T.Optional[ReturnValue] = None + + def set_parameters(self, params: T.List[Parameter]) -> None: + self.parameters.extend(params) + + def set_return_value(self, res: ReturnValue) -> None: + self.return_value = res + + +class Field(GIRElement): + """A field in a struct or union""" + def __init__(self, name: str, target: Type, writable: bool, readable: bool, private: bool = False, bits: int = 0): + super().__init__(name) + self.target = target + self.writable = writable + self.readable = readable + self.private = private + self.bits = bits + + +class Interface(Type): + def __init__(self, name: str, namespace: str, ctype: str, symbol_prefix: str, gtype: GType): + super().__init__(name=name, ctype=ctype, namespace=namespace) + self.symbol_prefix = symbol_prefix + self.gtype = gtype + self.methods: T.List[Method] = [] + self.virtual_methods: T.List[VirtualMethod] = [] + self.properties: T.Mapping[str, Property] = {} + self.signals: T.Mapping[str, Signal] = {} + self.functions: T.List[Function] = [] + self.fields: T.List[Field] = [] + self.prerequisite: T.Optional[str] = None ++ self.implementations: T.List[Type] = [] + + @property + def type_struct(self) -> T.Optional[str]: + if self.gtype is not None: + return self.gtype.type_struct + return self.ctype + + @property + def type_func(self) -> str: + return self.gtype.get_type + + def set_methods(self, methods: T.List[Method]) -> None: + self.methods.extend(methods) + + def set_virtual_methods(self, methods: T.List[VirtualMethod]) -> None: + self.virtual_methods.extend(methods) + + def set_properties(self, properties: T.List[Property]) -> None: + for p in properties: + self.properties[p.name] = p + + def set_signals(self, signals: T.List[Signal]) -> None: + for s in signals: + self.signals[s.name] = s + + def set_functions(self, functions: T.List[Function]) -> None: + self.functions.extend(functions) + + def set_fields(self, fields: T.List[Field]) -> None: + self.fields.extend(fields) + + def set_prerequisite(self, prerequisite: str) -> None: + self.prerequisite = prerequisite + + +class Class(Type): + def __init__(self, name: str, namespace: str, ctype: str, symbol_prefix: str, + gtype: GType, parent: T.Optional[Type] = None, + abstract: bool = False, fundamental: bool = False, + ref_func: T.Optional[str] = None, unref_func: T.Optional[str] = None): + super().__init__(name=name, ctype=ctype, namespace=namespace) + self.symbol_prefix = symbol_prefix + self.parent = parent + self.abstract = abstract + self.fundamental = fundamental + self.ref_func = ref_func + self.unref_func = unref_func + self.gtype = gtype + self.ancestors: T.List[Type] = [] + self.implements: T.List[Type] = [] + self.constructors: T.List[Function] = [] + self.methods: T.List[Method] = [] + self.virtual_methods: T.List[VirtualMethod] = [] + self.properties: T.Mapping[str, Property] = {} + self.signals: T.Mapping[str, Signal] = {} + self.functions: T.List[Function] = [] + self.fields: T.List[Field] = [] + self.callbacks: T.List[Callback] = [] ++ self.descendants: T.List[Type] = [] + + @property + def type_struct(self) -> T.Optional[str]: + if self.gtype is not None: + return self.gtype.type_struct + return None + + @property + def type_func(self) -> T.Optional[str]: + if self.gtype is not None: + return self.gtype.get_type + return self.ctype + + def set_constructors(self, ctors: T.List[Function]) -> None: + self.constructors.extend(ctors) + + def set_methods(self, methods: T.List[Method]) -> None: + self.methods.extend(methods) + + def set_virtual_methods(self, methods: T.List[VirtualMethod]) -> None: + self.virtual_methods.extend(methods) + + def set_properties(self, properties: T.List[Property]) -> None: + for p in properties: + self.properties[p.name] = p + + def set_signals(self, signals: T.List[Signal]) -> None: + for s in signals: + self.signals[s.name] = s + + def set_functions(self, functions: T.List[Function]) -> None: + self.functions.extend(functions) + + def set_implements(self, ifaces: T.List[Type]) -> None: + self.implements.extend(ifaces) + + def set_fields(self, fields: T.List[Field]) -> None: + self.fields.extend(fields) + + +class Boxed(Type): + def __init__(self, name: str, namespace: str, symbol_prefix: str, gtype: GType): + super().__init__(name=name, ctype=None, namespace=namespace) + self.symbol_prefix = symbol_prefix + self.gtype = gtype + self.functions: T.List[Function] = [] + + def set_functions(self, functions: T.List[Function]) -> None: + self.functions.extend(functions) + + +class Record(Type): + def __init__(self, name: str, namespace: str, ctype: str, symbol_prefix: str, + gtype: T.Optional[GType] = None, struct_for: T.Optional[str] = None, + disguised: bool = False): + super().__init__(name=name, ctype=ctype, namespace=namespace) + self.symbol_prefix = symbol_prefix + self.gtype = gtype + self.struct_for = struct_for + self.disguised = disguised + self.constructors: T.List[Function] = [] + self.methods: T.List[Method] = [] + self.functions: T.List[Function] = [] + self.fields: T.List[Field] = [] + + @property + def type_struct(self) -> T.Optional[str]: + if self.gtype is not None: + return self.gtype.type_struct + return self.ctype + + @property + def type_func(self) -> T.Optional[str]: + if self.gtype is not None: + return self.gtype.get_type + return None + + def set_constructors(self, ctors: T.List[Function]) -> None: + self.constructors.extend(ctors) + + def set_methods(self, methods: T.List[Method]) -> None: + self.methods.extend(methods) + + def set_functions(self, functions: T.List[Function]) -> None: + self.functions.extend(functions) + + def set_fields(self, fields: T.List[Field]) -> None: + self.fields.extend(fields) + + +class Union(Type): + def __init__(self, name: str, namespace: str, ctype: str, symbol_prefix: str, gtype: T.Optional[GType]): + super().__init__(name=name, ctype=ctype, namespace=namespace) + self.symbol_prefix = symbol_prefix + self.gtype = gtype + self.constructors: T.List[Function] = [] + self.methods: T.List[Method] = [] + self.functions: T.List[Function] = [] + self.fields: T.List[Field] = [] + + @property + def type_struct(self) -> T.Optional[str]: + if self.gtype is not None: + return self.gtype.type_struct + return self.ctype + + @property + def type_func(self) -> T.Optional[str]: + if self.gtype is not None: + return self.gtype.get_type + return None + + def set_constructors(self, ctors: T.List[Function]) -> None: + self.constructors.extend(ctors) + + def set_methods(self, methods: T.List[Method]) -> None: + self.methods.extend(methods) + + def set_functions(self, functions: T.List[Function]) -> None: + self.functions.extend(functions) + + def set_fields(self, fields: T.List[Field]) -> None: + self.fields.extend(fields) + + +class Namespace: + def __init__(self, name: str, version: str, identifier_prefix: T.List[str] = [], symbol_prefix: T.List[str] = []): + self.name = name + self.version = version + + self._shared_libraries: T.List[str] = [] + + self._aliases: T.Mapping[str, Alias] = {} + self._bitfields: T.Mapping[str, BitField] = {} + self._boxeds: T.Mapping[str, Boxed] = {} + self._callbacks: T.Mapping[str, Callback] = {} + self._classes: T.Mapping[str, Class] = {} + self._constants: T.Mapping[str, Constant] = {} + self._enumerations: T.Mapping[str, Enumeration] = {} + self._error_domains: T.Mapping[str, ErrorDomain] = {} + self._functions: T.Mapping[str, Function] = {} + self._function_macros: T.Mapping[str, FunctionMacro] = {} + self._interfaces: T.Mapping[str, Interface] = {} + self._records: T.Mapping[str, Record] = {} + self._unions: T.Mapping[str, Union] = {} + + self._symbols: T.Mapping[str, Type] = {} + self.repository: T.Optional[Repository] = None + + if identifier_prefix: + self.identifier_prefix = identifier_prefix + else: + self.identifier_prefix = [self.name] + if symbol_prefix: + self.symbol_prefix = symbol_prefix + else: + self.symbol_prefix = [self.name.lower()] + + def __str__(self): + return f"{self.name}-{self.version}" + + def add_shared_libraries(self, libs: T.List[str]) -> None: + self._shared_libraries.extend(libs) + + def get_shared_libraries(self) -> T.List[str]: + return self._shared_libraries + + def add_alias(self, alias: Alias) -> None: + self._aliases[alias.name] = alias + + def add_enumeration(self, enum: Enumeration) -> None: + self._enumerations[enum.name] = enum + + def add_error_domain(self, domain: ErrorDomain) -> None: + self._error_domains[domain.name] = domain + + def add_class(self, cls: Class) -> None: + self._classes[cls.name] = cls + + def add_constant(self, constant: Constant) -> None: + self._constants[constant.name] = constant + + def add_interface(self, interface: Interface) -> None: + self._interfaces[interface.name] = interface + + def add_boxed(self, boxed: Boxed) -> None: + self._boxeds[boxed.name] = boxed + + def add_record(self, record: Record) -> None: + self._records[record.name] = record + + def add_union(self, union: Union) -> None: + self._unions[union.name] = union + + def add_function(self, function: Function) -> None: + self._functions[function.name] = function + + def add_bitfield(self, bitfield: BitField) -> None: + self._bitfields[bitfield.name] = bitfield + + def add_function_macro(self, function: FunctionMacro) -> None: + self._function_macros[function.name] = function + + def add_callback(self, callback: Callback) -> None: + self._callbacks[callback.name] = callback + + def get_classes(self) -> T.List[Class]: + return self._classes.values() + + def get_constants(self) -> T.List[Constant]: + return self._constants.values() + + def get_enumerations(self) -> T.List[Enumeration]: + return self._enumerations.values() + + def get_error_domains(self) -> T.List[ErrorDomain]: + return self._error_domains.values() + + def get_aliases(self) -> T.List[Alias]: + return self._aliases.values() + + def get_interfaces(self) -> T.List[Interface]: + return self._interfaces.values() + + def get_boxeds(self) -> T.List[Boxed]: + return self._boxeds.values() + + def get_records(self) -> T.List[Record]: + return self._records.values() + + def get_effective_records(self) -> T.List[Record]: + def is_effective(r): + if "Private" in r.name and r.disguised: + return False + if r.struct_for is not None: + return False + return True + + return [x for x in self._records.values() if is_effective(x)] + + def get_unions(self) -> T.List[Union]: + return self._unions.values() + + def get_functions(self) -> T.List[Function]: + return self._functions.values() + + def get_bitfields(self) -> T.List[BitField]: + return self._bitfields.values() + + def get_function_macros(self) -> T.List[FunctionMacro]: + return self._function_macros.values() + + def get_effective_function_macros(self) -> T.List[FunctionMacro]: + def is_effective(f, ns): + # Lower-case identifiers are an automatic pass + if f.name.islower(): + return True + # Try to eliminate the GObject type macros from the pool + t = f.name.split('_') + # Skip "is-a" macros + if 'IS' in t: + return False + # Skip "get class/iface" macros + if 'GET' in t: + return False + # Re-assemble into what most likely is a type name + s = "".join([x.capitalize() if len(x) > 2 else x for x in t]) + # Skip "cast" macros + if ns.find_class(s) is not None: + return False + if ns.find_interface(s) is not None: + return False + if ns.find_record(s) is not None: + return False + # Anything that survived at this point is likely a valid function + # macro + return True + + return [x for x in self._function_macros.values() if is_effective(x, self)] + + def get_callbacks(self) -> T.List[Callback]: + return self._callbacks.values() + + def find_class(self, cls: str) -> T.Optional[Class]: + return self._classes.get(cls) + + def find_record(self, record: str) -> T.Optional[Record]: + return self._records.get(record) + + def find_interface(self, iface: str) -> T.Optional[Interface]: + return self._interfaces.get(iface) + + def find_union(self, union: str) -> T.Optional[Union]: + return self._unions.get(union) + + def find_enumeration(self, enum: str) -> T.Optional[Enumeration]: + return self._enumerations.get(enum) + + def find_bitfield(self, bitfield: str) -> T.Optional[BitField]: + return self._bitfields.get(bitfield) + + def find_error_domain(self, domain: str) -> T.Optional[ErrorDomain]: + return self._error_domains.get(domain) + + def find_alias(self, alias: str) -> T.Optional[Alias]: + return self._aliases.get(alias) + + def find_function(self, func: str) -> T.Optional[Function]: + if func in self._functions: + return self._functions.get(func) + if func in self._function_macros: + return self._function_macros.get(func) + return None + + def find_real_type(self, name: str) -> T.Optional[Type]: + if name in self._aliases: + return self._aliases[name] + if name in self._bitfields: + return self._bitfields[name] + if name in self._callbacks: + return self._callbacks[name] + if name in self._constants: + return self._constants[name] + if name in self._enumerations: + return self._enumerations[name] + if name in self._error_domains: + return self._error_domains[name] + if name in self._classes: + return self._classes[name] + if name in self._interfaces: + return self._interfaces[name] + if name in self._records: + return self._records[name] + if name in self._unions: + return self._unions[name] + return None + + def find_symbol(self, name: str) -> T.Optional[Type]: + return self._symbols.get(name) + + def find_prerequisite_type(self, name: str) -> T.Optional[Type]: + if name in self._classes: + return self._classes[name] - if name is self._interfaces: ++ if name in self._interfaces: + return self._interfaces[name] + return None + + +class Repository: + def __init__(self): + self.includes: T.Mapping[str, Repository] = {} + self.packages: T.List[Package] = [] + self.c_includes: T.List[CInclude] = [] + self.types: T.Mapping[str, T.List[Type]] = {} + self._namespaces: T.List[Namespace] = [] + self.girfile: T.Optional[str] = None + + def add_namespace(self, ns: Namespace) -> None: + self._namespaces.append(ns) + ns.repository = self + + def get_namespace(self, ns: str) -> T.Optional[Namespace]: + for namespace in self._namespaces: + if namespace.name == ns: + return namespace + return None + + def find_included_namespace(self, ns: str) -> T.Optional[Namespace]: + for repo_name in self.includes: + repo = self.includes[repo_name] + if repo.namespace.name == ns: + return repo.namespace + return None + ++ def _lookup_type(self, name: str) -> T.Optional[Type]: ++ types = self.types.get(name) ++ if types is None: ++ return None ++ for t in types: ++ if t.resolved: ++ return t ++ return types[0] ++ + def resolve_empty_ctypes(self, seen_types: T.Mapping[str, T.List[Type]]) -> None: + for fqtn in seen_types: + types = seen_types[fqtn] + resolved_types = [t for t in types if t.resolved] + if len(resolved_types) == 0: + ns, name = fqtn.split('.', 1) + backstop = f"{self.namespace.identifier_prefix[0]}{name}" + resolved_types.append(Type(fqtn, backstop)) + self.types[fqtn] = resolved_types + log.debug(f"Type: {fqtn}: {resolved_types}") + + def resolve_interface_requires(self) -> None: + def find_prerequisite_type(includes, ns, name): - for repo in includes.values(): - if repo.namespace.name != ns: - continue - prereq = repo.namespace.find_prerequisite_type(name) - if prereq is not None: - return Type(name=f"{repo.namespace.name}.{prereq.name}", ctype=prereq.ctype) - return None ++ repository = includes.get(ns) ++ if repository is None: ++ return None ++ prereq = repository.namespace.find_prerequisite_type(name) ++ # If the prerequisite type is unqualified, then we qualify it here ++ if '.' not in prereq.name: ++ prereq.name = f"{repository.namespace.name}.{prereq.name}" ++ return prereq + + ifaces = self.namespace.get_interfaces() + for iface in ifaces: + if iface.prerequisite is None: + continue + prerequisite = None + if '.' in iface.prerequisite.name: + ns, name = iface.prerequisite.name.split('.', 1) + if ns == self.namespace.name: + prerequisite = self.namespace.find_prerequisite_type(name) + else: + prerequisite = find_prerequisite_type(self.includes, ns, name) + else: + prerequisite = self.namespace.find_prerequisite_type(iface.prerequisite.name) + if prerequisite is not None: + if prerequisite.ctype is None: - t = self.find_type(prerequisite.name) - prerequisite.ctype = t.ctype ++ if '.' not in prerequisite.name: ++ name = f"{self.namespace.name}.{prerequisite.name}" ++ else: ++ name = prerequisite.name ++ t = self._lookup_type(name) ++ if t is not None: ++ prerequisite.ctype = t.ctype ++ else: ++ # This is kind of a kludge, but apparently we can get into ++ # class definitions missing a c:type; if that happens, we ++ # take the identifier prefix of the namespace and append the ++ # class name, because that's the inverse of how g-ir-scanner ++ # determines the class name ++ prerequisite.ctype = f"{self.namespace.identifier_prefix[0]}{prerequisite.name}" + iface.prerequisite = prerequisite + log.debug(f"Prerequisite type for interface {iface}: {iface.prerequisite}") + - def resolve_class_type(self) -> None: ++ def resolve_class_ctype(self) -> None: + classes = self.namespace.get_classes() + for cls in classes: + if cls.ctype is None: + if '.' not in cls.name: + name = f"{self.namespace.name}.{cls.name}" + else: + name = cls.name - t = self.find_type(name) ++ t = self._lookup_type(name) + if t is not None: + cls.ctype = t.base_ctype + else: + # This is kind of a kludge, but apparently we can get into + # class definitions missing a c:type; if that happens, we + # take the identifier prefix of the namespace and append the + # class name, because that's the inverse of how g-ir-scanner + # determines the class name + cls.ctype = f"{self.namespace.identifier_prefix[0]}{cls.name}" + log.debug(f"Updated C type for {cls}") + + def resolve_class_implements(self) -> None: + def find_interface_type(includes, ns, name): - for repo in includes.values(): - if repo.namespace.name != ns: - continue - iface = repo.namespace.find_interface(name) - if iface is not None: - return Type(name=f"{repo.namespace.name}.{iface.name}", ctype=iface.ctype) - return None ++ repository = includes.get(ns) ++ if repository is None: ++ return None ++ iface = repository.namespace.find_interface(name) ++ # If the interface type is unqualified, then we qualify it here ++ if '.' not in iface.name: ++ iface.name = f"{repository.namespace.name}.{iface.name}" ++ return iface + + classes = self.namespace.get_classes() + for cls in classes: + if cls.implements is None: + continue + implements = cls.implements + cls.implements = [] + for iface in implements: + if '.' in iface.name: + ns, name = iface.name.split('.', 1) + if ns == self.namespace.name: + iface_type = self.namespace.find_interface(name) + else: + iface_type = find_interface_type(self.includes, ns, name) + else: + iface_type = self.namespace.find_interface(iface.name) + if iface_type is not None: + if iface_type.ctype is None: - t = self.find_type(iface_type.name) ++ t = self._lookup_type(iface_type.name) + iface_type.ctype = t.ctype + cls.implements.append(iface_type) + log.debug(f"Interfaces implemented by {cls}: {cls.implements}") + + def resolve_class_ancestors(self) -> None: + def find_parent_class(includes, ns, name): + repository = includes.get(ns) + if repository is None: + return None + parent_class = repository.namespace.find_class(name) + # If the parent type is unqualified, then we qualify it here + if '.' not in parent_class.name: + parent_class.name = f"{repository.namespace.name}.{parent_class.name}" + return parent_class + + classes = self.namespace.get_classes() + for cls in classes: + if cls.parent is None: + continue + ancestors = [] + parent = cls.parent + while parent is not None: + if '.' in parent.name: + ns, name = parent.name.split('.') + if ns == self.namespace.name: + real_parent = self.namespace.find_class(name) + else: + real_parent = find_parent_class(self.includes, ns, name) + else: + real_parent = self.namespace.find_class(parent.name) + if real_parent is None: + break + if real_parent.parent is not None and real_parent.parent.name == parent.name: + log.warning(f"Found a loop in the ancestors for {cls}: {real_parent} matches {parent}") + break + if real_parent.ctype is None: + log.debug(f"Looking up C type for {parent.fqtn}") - t = self.find_type(parent.name) ++ t = self._lookup_type(parent.name) + real_parent.ctype = t.ctype + log.debug(f"Adding ancestor {real_parent} for {cls}") + ancestors.append(real_parent) + parent = real_parent.parent + cls.ancestors = ancestors + cls.parent = ancestors[0] + log.debug(f"Ancestors for {cls}: parent: {cls.parent}, ancestors: {cls.ancestors}") + ++ def resolve_class_descendants(self) -> None: ++ seen_parents = {} ++ for cls in self.namespace.get_classes(): ++ if cls.parent is not None: ++ seen_parents.setdefault(cls.parent.name, []).append(cls) ++ for name, descendants in seen_parents.items(): ++ if name in self.namespace._classes: ++ self.namespace._classes[name].descendants = descendants ++ + def resolve_moved_to(self) -> None: + functions = list(self.namespace.get_functions()) + old_len = len(functions) + for func in functions[:]: + if func.moved_to is None: + continue + moved_type, moved_func_name = func.moved_to.split('.') + real_type = self.namespace.find_real_type(moved_type) + if real_type is None: + continue + self.namespace._functions.pop(func.name) # XXX: Add accessor + new_len = len(self.namespace._functions) + diff = old_len - new_len + log.debug(f"Removed {old_len} - {new_len} functions: {diff}") + + def resolve_symbols(self) -> None: + symbols: T.Mapping[str, Type] = {} + for func in self.namespace.get_functions(): + symbols[func.identifier] = func + for func in self.namespace.get_function_macros(): + symbols[func.identifier] = func + for cls in self.namespace.get_classes(): + for m in cls.constructors: + symbols[m.identifier] = cls + for m in cls.methods: + symbols[m.identifier] = cls + for m in cls.functions: + symbols[m.identifier] = cls + for iface in self.namespace.get_interfaces(): + for m in iface.methods: + symbols[m.identifier] = iface + for m in iface.functions: + symbols[m.identifier] = iface + for record in self.namespace.get_records(): + for m in record.constructors: + symbols[m.identifier] = record + for m in record.methods: + symbols[m.identifier] = record + for m in record.functions: + symbols[m.identifier] = record + for union in self.namespace.get_unions(): + for m in union.constructors: + symbols[m.identifier] = union + for m in union.methods: + symbols[m.identifier] = union + for m in union.functions: + symbols[m.identifier] = union + self.namespace._symbols = symbols + ++ def resolve_interface_implementations(self) -> None: ++ seen_impls = {} ++ for iface in self.namespace.get_interfaces(): ++ for cls in self.namespace.get_classes(): ++ if cls.implements is None: ++ continue ++ if iface in cls.implements: ++ seen_impls.setdefault(iface.name, []).append(cls) ++ for iface, seen in seen_impls.items(): ++ if iface in self.namespace._interfaces: ++ self.namespace._interfaces[iface].implementations = seen ++ + def get_class_hierarchy(self, root=None): + flat_tree = [] + seen_types = {} + + def window(iterable, size=2): + i = iter(iterable) + win = [] + for e in range(0, size): + win.append(next(i)) + yield win + for e in i: + win = win[1:] + [e] + yield win + + for cls in self.namespace.get_classes(): + if cls.parent is None: + flat_tree.append((cls.name, None)) + continue + + if len(cls.ancestors) < 2: + flat_tree.append((cls.name, cls.ancestors[0].name)) + else: + flat_tree.append((cls.name, cls.ancestors[0].name)) + for chunk in window(cls.ancestors, size=2): + if chunk[0].name in seen_types: + continue + if len(chunk) == 2: + flat_tree.append((chunk[0].name, chunk[1].name)) + else: + flat_tree.append((chunk[0].name, None)) + seen_types[chunk[0].name] = 1 + + def subtree(cls, rel): + return { + v: subtree(v, rel) + for v in [x[0] for x in rel if x[1] == cls] + } + + return subtree(root, flat_tree) + + @property + def namespace(self) -> T.Optional[Namespace]: + return self._namespaces[0] + - def find_type(self, name: str) -> T.Optional[Type]: - types = self.types.get(name) - if types is None: - return None - for t in types: - if t.resolved: - return t - return types[0] ++ def find_type(self, name: str, ns: T.Optional[str] = None) -> T.Optional[T.Tuple[Namespace, Type]]: ++ if ns is None or self.namespace.name == ns: ++ res = self.namespace.find_real_type(name) ++ if res is not None: ++ return (self.namespace, res) ++ for repo in self.includes.values(): ++ if ns is not None and ns != repo.namespace.name: ++ continue ++ res = repo.namespace.find_real_type(name) ++ if res is not None: ++ return (repo.namespace, res) ++ return None ++ ++ def find_symbol(self, name: str) -> T.Optional[T.Tuple[Namespace, Type]]: ++ log.debug(f"Looking for symbol {name} in current namespace {self.namespace.name}") ++ res = self.namespace.find_symbol(name) ++ if res is not None: ++ return (self.namespace, res) ++ for repo in self.includes.values(): ++ log.debug(f"Looking for symbol {name} in namespace {repo.namespace.name}") ++ res = repo.namespace.find_symbol(name) ++ if res is not None: ++ return (repo.namespace, res) ++ return None ++ ++ def find_class(self, name: str, ns: T.Optional[str] = None) -> T.Optional[T.Tuple[Namespace, Type]]: ++ if ns is None or self.namespace.name == ns: ++ res = self.namespace.find_class(name) ++ if res is not None: ++ return (self.namespace, res) ++ for repo in self.includes.values(): ++ if ns is not None and ns != repo.namespace.name: ++ continue ++ res = repo.namespace.find_class(name) ++ if res is not None: ++ return (repo.namespace, res) ++ return None ++ ++ def find_interface(self, name: str, ns: T.Optional[str] = None) -> T.Optional[T.Tuple[Namespace, Type]]: ++ if ns is None or self.namespace.name == ns: ++ res = self.namespace.find_interface(name) ++ if res is not None: ++ return (self.namespace, res) ++ for repo in self.includes.values(): ++ if ns is not None and ns != repo.namespace.name: ++ continue ++ res = repo.namespace.find_interface(name) ++ if res is not None: ++ return (repo.namespace, res) ++ return None diff --cc subprojects/gi-docgen/gidocgen/gir/parser.py index 92b3cbfe85,0000000000..7637f194a3 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/gir/parser.py +++ b/subprojects/gi-docgen/gidocgen/gir/parser.py @@@ -1,1012 -1,0 +1,1057 @@@ +# SPDX-FileCopyrightText: 2020 GNOME Foundation +# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +import os +import typing as T +import xml.etree.ElementTree as ET + +from .. import log +from . import ast + +GI_NAMESPACES = { + 'core': "http://www.gtk.org/introspection/core/1.0", + 'c': "http://www.gtk.org/introspection/c/1.0", + 'glib': "http://www.gtk.org/introspection/glib/1.0", +} + - FUNDAMENTAL_TYPES = [ ++FUNDAMENTAL_INTEGRAL_TYPES = [ + 'gint8', 'guint8', 'int8_t', 'uint8_t', + 'gint16', 'guint16', 'int16_t', 'uint16_t', + 'gint32', 'guint32', 'int32_t', 'uint32_t', + 'gint64', 'guint64', 'int64_t', 'uint64_t', - 'gint', 'guint', 'int', 'unsigned', 'unsigned int', ++ 'gint', 'int', ++ 'guint', 'unsigned', 'unsigned int', + 'gfloat', 'float', + 'gdouble', 'double', 'long double', + 'gchar', 'guchar', 'char', 'unsigned char', + 'gshort', 'gushort', 'short', 'unsigned short', + 'glong', 'gulong', 'long', 'unsigned long', - 'utf8', 'filename', + 'gunichar', - 'gpointer', 'gconstpointer', - 'gchar*', 'char*', 'guchar*', + 'gsize', 'gssize', 'size_t', + 'gboolean', 'bool', + 'va_list', +] + ++FUNDAMENTAL_TYPES = FUNDAMENTAL_INTEGRAL_TYPES + [ ++ 'gpointer', 'gconstpointer', ++ 'gchar*', 'char*', 'guchar*', ++ 'utf8', 'filename', ++] ++ +GLIB_ALIASES = { + 'gchar': 'char', + 'gdouble': 'double', + 'gfloat': 'float', + 'gint': 'int', + 'glong': 'long', + 'gshort': 'short', +} + +FUNDAMENTAL_CTYPES = { ++ 'utf8': 'char*', ++ 'filename': 'char*', + 'GObject.Object': 'GObject*', + 'GObject.InitiallyUnowned': 'GInitiallyUnowned*', + 'GObject.ParamSpec': 'GObject.ParamSpec*', +} + + +def _corens(tag: str) -> str: + return f"{{{GI_NAMESPACES['core']}}}{tag}" + + +def _glibns(tag: str) -> str: + return f"{{{GI_NAMESPACES['glib']}}}{tag}" + + +def _cns(tag: str) -> str: + return f"{{{GI_NAMESPACES['c']}}}{tag}" + + +class GirParser: + def __init__(self, search_paths=[]): + self._search_paths = search_paths + self._repository = None + self._dependencies = {} + self._seen_types = {} + self._current_namespace = [] + + def append_search_path(self, path: str) -> None: + """Append a path to the list of search paths""" + self._search_paths.append(path) + + def prepend_search_paths(self, path: str) -> None: + """Prepend a path to the list of search paths""" + self._search_paths = [path] + self._search_paths + + def parse(self, girfile: T.TextIO) -> None: + """Parse @girfile""" + log.debug(f"Loading GIR for {girfile}") + tree = ET.parse(girfile) + repository = self._parse_tree(tree.getroot()) + if repository is None: + log.error(f"Could not parse GIR {girfile}") + else: + if isinstance(girfile, str): + repository.girfile = girfile + else: + repository.girfile = girfile.name + self._repository = repository + self._repository.resolve_empty_ctypes(self._seen_types) - self._repository.resolve_interface_requires() - self._repository.resolve_class_type() ++ self._repository.resolve_class_ctype() + self._repository.resolve_class_implements() + self._repository.resolve_class_ancestors() ++ self._repository.resolve_class_descendants() ++ self._repository.resolve_interface_requires() ++ self._repository.resolve_interface_implementations() + self._repository.resolve_moved_to() + self._repository.resolve_symbols() + + def get_repository(self, name: T.Optional[str] = None) -> T.Optional[ast.Repository]: + if name is None: + return self._repository + else: + return self._dependencies[name] + + def _push_namespace(self, ns: ast.Namespace) -> None: - assert(ns not in self._current_namespace) ++ assert ns not in self._current_namespace + self._current_namespace.append(ns) + + def _pop_namespace(self) -> None: + self._current_namespace.pop() + + def _get_namespace(self) -> T.Optional[ast.Namespace]: + if len(self._current_namespace) == 0: + return None + return self._current_namespace[len(self._current_namespace) - 1] + + def _lookup_type(self, name: str, ctype: T.Optional[str] = None) -> ast.Type: + """Look up a type, and if not found, register it""" ++ is_fundamental = False + if name in FUNDAMENTAL_TYPES: + if name in GLIB_ALIASES: + fqtn = GLIB_ALIASES[name] + else: + fqtn = name ++ is_fundamental = True + elif name == 'GType': + # This is messy, because GType is part of GObject, but GLib ends up + # registering it first + fqtn = 'GObject.Type' ++ is_fundamental = True + elif '.' in name: + fqtn = name + else: + ns = self._get_namespace() + if ns is not None: + fqtn = f"{ns.name}.{name}" + else: + log.debug(f"Unqualified type name {name} found") + fqtn = name + if ctype is None and fqtn in FUNDAMENTAL_TYPES: + for t in FUNDAMENTAL_TYPES: + if t == fqtn: + ctype = t + break + if ctype is None and fqtn in FUNDAMENTAL_CTYPES: + ctype = FUNDAMENTAL_CTYPES[fqtn] + found_types = self._seen_types.get(fqtn) + if found_types is not None: + if ctype is not None: + for t in found_types: + if t.resolved and t.ctype == ctype: + log.debug(f"Found seen type: {t} (with ctype)") + return t - t = ast.Type(name=fqtn, ctype=ctype) ++ t = ast.Type(name=fqtn, ctype=ctype, is_fundamental=is_fundamental) + found_types.append(t) + log.debug(f"Seen new type: {t} (with ctype)") + return t + log.debug(f"Found seen type: {found_types[0]}") + return found_types[0] + # First time we saw this type - res = ast.Type(name=fqtn, ctype=ctype) ++ res = ast.Type(name=fqtn, ctype=ctype, is_fundamental=is_fundamental) + self._seen_types[fqtn] = [res] + log.debug(f"Seen new type: {res}") + return res + + def _parse_dependency(self, include: ast.Include) -> None: + if self._dependencies.get(include.name, None) is not None: + log.debug(f"Dependency {include} already parsed") + return + found = False + for base_path in self._search_paths: + girfile = os.path.join(base_path, f"{include}.gir") + if os.path.exists(girfile) and os.path.isfile(girfile): + log.debug(f"Loading GIR for dependency {include} at {girfile}") + tree = ET.parse(girfile) + repository = self._parse_tree(tree.getroot()) + if repository is not None: + repository.girfile = girfile ++ repository.resolve_moved_to() ++ repository.resolve_symbols() + ns = repository.namespace + self._dependencies[ns.name] = repository + found = True + break + if not found: + log.error(f"Could not find GIR dependency in the search paths: {include}") + + def _parse_tree(self, root: ET.Element) -> ast.Repository: + assert root.tag == _corens('repository') + + includes: T.List[ast.Include] = [] + c_includes: T.List[str] = [] + packages: T.List[str] = [] + + for node in root: + if node.tag == _corens('include'): + includes.append(self._parse_include(node)) + elif node.tag == _cns('include'): + c_includes.append(self._parse_c_include(node)) + elif node.tag == _corens('package'): + packages.append(self._parse_package(node)) + + ns = root.find(_corens('namespace')) + assert ns is not None + + identifier_prefixes = ns.attrib.get(_cns('identifier-prefixes')) + if identifier_prefixes is not None: + identifier_prefixes = identifier_prefixes.split(',') + symbol_prefixes = ns.attrib.get(_cns('symbol-prefixes')) + if symbol_prefixes is not None: + symbol_prefixes = symbol_prefixes.split(',') + + namespace = ast.Namespace(ns.attrib['name'], ns.attrib['version'], identifier_prefixes, symbol_prefixes) + shared_libs = ns.attrib.get('shared-library') + if shared_libs: + namespace.add_shared_libraries(shared_libs.split(',')) + + repository = ast.Repository() + repository.c_includes = c_includes + repository.packages = packages + + for include in includes: + log.debug(f"Parsing dependency {include}") + self._parse_dependency(include) + + repository.includes = self._dependencies + + repository.add_namespace(namespace) + + parse_sections: T.Mapping[str, T.Callable[[ET.Element, ast.Repository, ast.Namespace], T.Any]] = { + _corens('alias'): self._parse_alias, + _corens('bitfield'): self._parse_bitfield, + _glibns('boxed'): self._parse_boxed, + _corens('callback'): self._parse_callback, + _corens('class'): self._parse_class, + _corens('constant'): self._parse_constant, + _corens('enumeration'): self._parse_enumeration, + _corens('function-macro'): self._parse_function_macro, + _corens('function'): self._parse_function, + _corens('interface'): self._parse_interface, + _corens('record'): self._parse_record, + _corens('union'): self._parse_union, + } + + self._push_namespace(namespace) + + for node in ns: + parser_method = parse_sections.get(node.tag, None) + if parser_method is not None: + parser_method(node, repository, namespace) + + self._pop_namespace() + + return repository + + def _parse_include(self, node: ET.Element) -> ast.Include: + return ast.Include(node.attrib['name'], node.attrib['version']) + + def _parse_c_include(self, node: ET.Element) -> str: + return node.attrib['name'] + + def _parse_package(self, node: ET.Element) -> str: + return node.attrib['name'] + + def _maybe_parse_doc(self, node: ET.Element) -> T.Optional[ast.Doc]: + child = node.find('core:doc', GI_NAMESPACES) + if child is None: + return None + + content = child.text or "" + + return ast.Doc(content=content, filename=child.attrib['filename'], line=int(child.attrib['line'])) + + def _maybe_parse_source_position(self, node: ET.Element) -> T.Optional[ast.SourcePosition]: + child = node.find('core:source-position', GI_NAMESPACES) + if child is None: + return None + + return ast.SourcePosition(filename=child.attrib['filename'], line=int(child.attrib['line'])) + + def _maybe_parse_deprecated_doc(self, node: ET.Element) -> T.Optional[str]: + child = node.find('core:doc-deprecated', GI_NAMESPACES) + if child is None: + return None + + return "".join(child.itertext()) + + def _maybe_parse_attributes(self, node: ET.Element) -> T.Optional[T.Mapping[str, str]]: + children = node.findall('core:attribute', GI_NAMESPACES) + if children is None: + return None + + attrs = {} + for child in children: + name = child.attrib.get('name') + value = child.attrib.get('value') + if name is not None: + attrs[name] = value + return attrs + + def _maybe_parse_docs(self, node: ET.Element, element: ast.GIRElement) -> None: + doc = self._maybe_parse_doc(node) + if doc is not None: + element.set_doc(doc) + source_pos = self._maybe_parse_source_position(node) + if source_pos is not None: + element.set_source_position(source_pos) + attrs = self._maybe_parse_attributes(node) + if attrs is not None: + element.set_attributes(attrs) + stability = node.attrib.get('stability') + if stability is not None: + element.set_stability(stability) + deprecated = node.attrib.get('deprecated') + if deprecated is not None: + deprecated_since = node.attrib.get('deprecated-version') + deprecated_doc = self._maybe_parse_deprecated_doc(node) + if deprecated_doc is not None: + element.set_deprecated(deprecated_doc, deprecated_since) + + def _parse_ctype(self, node: ET.Element) -> ast.Type: + ctype: T.Optional[ast.Type] = None + + child = node.find('core:array', GI_NAMESPACES) + if child is not None: + name = node.attrib.get('name') - zero_terminated = int(child.attrib.get('zero-terminated', 0)) - fixed_size = int(child.attrib.get('fixed-size', -1)) - length = int(child.attrib.get('length', -1)) + array_type = child.attrib.get(_cns('type')) ++ attr_zero_terminated = child.attrib.get('zero-terminated') ++ attr_fixed_size = child.attrib.get('fixed-size') ++ attr_length = child.attrib.get('length') + + target: T.Optional[ast.Type] = None + child_type = child.find('core:type', GI_NAMESPACES) + if child_type is not None: + ttype = child_type.attrib.get(_cns('type')) + tname = child_type.attrib.get('name') + if tname is None and ttype is not None: - log.debug(f"Unnabled element type {ttype}") ++ log.debug(f"Unlabled element type {ttype}") + target = ast.Type(name=ttype.replace('*', ''), ctype=ttype) + if tname == 'none' and ttype == 'void': + target = ast.VoidType() - elif tname != 'gpointer' and ttype == 'gpointer': ++ elif ttype == 'gpointer' and tname in FUNDAMENTAL_INTEGRAL_TYPES: ++ # API returning a pointer with an overridden fundamental type, ++ # like in-out/out signal arguments ++ ctype = self._lookup_type(name=tname, ctype=f"{tname}*") ++ elif ttype == 'gpointer' and tname != 'gpointer': + # API returning gpointer to avoid casting + target = self._lookup_type(name=tname) - else: ++ elif tname: + target = self._lookup_type(name=tname, ctype=ttype) ++ else: ++ target = ast.VoidType() + else: + target = ast.VoidType() - ctype = ast.ArrayType(name=name, zero_terminated=zero_terminated, fixed_size=fixed_size, length=length, ++ # This sort of complete brain damage is par for the course in g-i, sadly; I really ++ # need to go into it with a sledgehammer and make the output complete, instead of ++ # relying on assumptions made in 2010. ++ zero_terminated = False ++ fixed_size = -1 ++ length = -1 ++ if attr_zero_terminated is not None: ++ zero_terminated = bool(attr_zero_terminated == '1') ++ else: ++ zero_terminated = bool(attr_fixed_size is None and attr_length is None) ++ if attr_fixed_size is not None: ++ fixed_size = int(attr_fixed_size) ++ if attr_length is not None: ++ length = int(attr_length) ++ ++ ctype = ast.ArrayType(name=name, zero_terminated=zero_terminated, ++ fixed_size=fixed_size, length=length, + ctype=array_type, value_type=target) + else: + child = node.find('core:type', GI_NAMESPACES) + if child is not None: + ttype = child.attrib.get(_cns('type')) + tname = child.attrib.get('name') + if tname is None and ttype is None: + log.debug(f"Found empty type annotation for node {node.tag}") + ctype = ast.VoidType() + elif tname is None and ttype is not None: + log.debug(f"Unnamed type {ttype}") + ctype = ast.Type(name=ttype.replace('*', ''), ctype=ttype) + elif tname == 'none' and ttype == 'void': + ctype = None + elif tname in ['GLib.List', 'GLib.SList']: + child_type = child.find('core:type', GI_NAMESPACES) + if child_type is not None: + etname = child_type.attrib.get('name', 'gpointer') + etype = self._lookup_type(name=etname) + ctype = ast.ListType(name=tname, ctype=ttype, value_type=etype) + else: + ctype = self._lookup_type(name=tname, ctype=ttype) + elif tname in ['GList.HashTable']: + child_types = child.findall('core:type', GI_NAMESPACES) + if child_types is not None and len(child_types) == 2: + ktname = child_types[0].attrib.get('name', 'gpointer') + vtname = child_types[1].attrib.get('name', 'gpointer') + ctype = ast.MapType(name=tname, ctype=ttype, + key_type=ast.Type(ktname), + value_type=ast.Type(vtname)) + else: + ctype = self._lookup_type(name=tname, ctype=ttype) - elif tname != 'gpointer' and ttype == 'gpointer': ++ elif ttype == 'gpointer' and tname in FUNDAMENTAL_INTEGRAL_TYPES: ++ # API returning a pointer with an overridden fundamental type, ++ # like in-out/out signal arguments ++ ctype = self._lookup_type(name=tname, ctype=f"{tname}*") ++ elif ttype == 'gpointer' and tname != 'gpointer': + # API returning gpointer to avoid casting + ctype = self._lookup_type(name=tname) + else: + ctype = self._lookup_type(name=tname, ctype=ttype) + else: + child = node.find('core:varargs', GI_NAMESPACES) + if child is not None: + ctype = ast.VarArgs() + + if ctype is None: + ctype = ast.VoidType() + + return ctype + + def _parse_alias(self, node: ET.Element, repo: ast.Repository, ns: ast.Namespace) -> None: + child = node.find('core:type', GI_NAMESPACES) + assert child is not None + + name = node.attrib.get('name') + ctype = node.attrib.get(_cns('type')) + + alias_type = ast.Type(name=child.attrib['name'], ctype=child.attrib.get(_cns('type'))) + + res = ast.Alias(name=name, namespace=ns.name, ctype=ctype, target=alias_type) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_version(node.attrib.get('version')) + self._maybe_parse_docs(node, res) + + ns.add_alias(res) + + def _parse_callback_field(self, node: ET.Element) -> ast.Callback: + name = node.attrib.get('name') + ctype = node.attrib.get(_cns('type')) + throws = node.attrib.get('throws', '0') == '1' + + child = node.find('core:return-value', GI_NAMESPACES) + return_value = self._parse_return_value(child) + + children = node.findall('./core:parameters/core:parameter', GI_NAMESPACES) + params = [] + for child in children: + params.append(self._parse_parameter(child)) + + res = ast.Callback(name=name, namespace=None, ctype=ctype, throws=throws) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_version(node.attrib.get('version')) + res.set_parameters(params) + res.set_return_value(return_value) + self._maybe_parse_docs(node, res) + return res + + def _parse_callback(self, node: ET.Element, repo: ast.Repository, ns: ast.Namespace) -> None: + name = node.attrib.get('name') + ctype = node.attrib.get(_cns('type')) + throws = node.attrib.get('throws', '0') == '1' + + child = node.find('core:return-value', GI_NAMESPACES) + return_value = self._parse_return_value(child) + + children = node.findall('./core:parameters/core:parameter', GI_NAMESPACES) + params = [] + for child in children: + params.append(self._parse_parameter(child)) + + res = ast.Callback(name=name, namespace=ns.name, ctype=ctype, throws=throws) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_version(node.attrib.get('version')) + res.set_parameters(params) + res.set_return_value(return_value) + self._maybe_parse_docs(node, res) + ns.add_callback(res) + + def _parse_constant(self, node: ET.Element, repo: ast.Repository, ns: T.Optional[ast.Namespace]) -> None: + child = node.find('core:type', GI_NAMESPACES) + assert child is not None + + name = node.attrib.get('name') + ctype = node.attrib.get(_cns('type')) + value = node.attrib.get('value') + + const_type = ast.Type(name=child.attrib['name'], ctype=child.attrib.get(_cns('type'))) + + res = ast.Constant(name=name, namespace=ns.name, ctype=ctype, value=value, target=const_type) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + self._maybe_parse_docs(node, res) + + ns.add_constant(res) + + def _parse_return_value(self, node: ET.Element) -> ast.ReturnValue: + transfer = node.attrib.get('transfer-ownership', 'none') + nullable = node.attrib.get('nullable', '0') == '1' + closure = int(node.attrib.get('closure', -1)) + destroy = int(node.attrib.get('destroy', -1)) + scope = node.attrib.get('scope') + + ctype = self._parse_ctype(node) + + res = ast.ReturnValue(transfer=transfer, target=ctype, nullable=nullable, closure=closure, + destroy=destroy, scope=scope) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + self._maybe_parse_docs(node, res) + + return res + + def _parse_parameter(self, node: ET.Element, is_instance_param: bool = False) -> ast.Parameter: + name = node.attrib.get('name') + direction = node.attrib.get('direction', 'in') + transfer = node.attrib.get('transfer-ownership', 'none') + nullable = node.attrib.get('nullable', '0') == '1' + optional = node.attrib.get('optional', '0') == '1' + caller_allocates = node.attrib.get('caller-allocates', '1') == '1' + closure = int(node.attrib.get('closure', -1)) + destroy = int(node.attrib.get('destroy', -1)) + scope = node.attrib.get('scope') + + ctype = self._parse_ctype(node) + + res = ast.Parameter(name=name, direction=direction, transfer=transfer, target=ctype, + optional=optional, nullable=nullable, caller_allocates=caller_allocates, + closure=closure, destroy=destroy, scope=scope) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + self._maybe_parse_docs(node, res) + + return res + + def _parse_type_function(self, node: ET.Element, ns: T.Optional[ast.Namespace] = None) -> ast.Function: + name = node.attrib.get('name') + identifier = node.attrib.get(_cns('identifier')) + throws = node.attrib.get('throws', '0') == '1' + shadows = node.attrib.get('shadows') + shadowed_by = node.attrib.get('shadowed-by') + moved_to = node.attrib.get('moved-to') + + child = node.find('core:return-value', GI_NAMESPACES) + return_value = self._parse_return_value(child) + + children = node.findall('./core:parameters/core:parameter', GI_NAMESPACES) + params = [] + for child in children: + params.append(self._parse_parameter(child)) + + if ns is not None: + namespace = ns.name + else: + namespace = None + + res = ast.Function(name=name, namespace=namespace, identifier=identifier, throws=throws) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_version(node.attrib.get('version')) + res.set_return_value(return_value) + res.set_parameters(params) + res.set_shadows(shadows) + res.set_shadowed_by(shadowed_by) + res.set_moved_to(moved_to) + self._maybe_parse_docs(node, res) + return res + + def _parse_function(self, node: ET.Element, repo: ast.Repository, ns: ast.Namespace) -> None: + res = self._parse_type_function(node, ns) + ns.add_function(res) + + def _parse_function_macro(self, node: ET.Element, repo: ast.Repository, ns: ast.Namespace) -> None: + name = node.attrib.get('name') + identifier = node.attrib.get(_cns('identifier')) + + children = node.findall('./core:parameters/core:parameter', GI_NAMESPACES) + params = [] + for child in children: + params.append(self._parse_parameter(child)) + + res = ast.FunctionMacro(name=name, namespace=ns.name, identifier=identifier) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_parameters(params) + res.set_return_value(ast.ReturnValue(transfer='none', + target=ast.VoidType(), + nullable=False, + closure=-1, destroy=-1, + scope=None)) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_version(node.attrib.get('version')) + self._maybe_parse_docs(node, res) + ns.add_function_macro(res) + + def _parse_method(self, node: ET.Element) -> ast.Method: + name = node.attrib.get('name') + identifier = node.attrib.get(_cns('identifier')) + throws = node.attrib.get('throws', '0') == '1' + shadows = node.attrib.get('shadows') + shadowed_by = node.attrib.get('shadowed-by') ++ set_property = node.attrib.get(_glibns('set-property')) ++ get_property = node.attrib.get(_glibns('get-property')) + + child = node.find('core:return-value', GI_NAMESPACES) + return_value = self._parse_return_value(child) + + child = node.find('./core:parameters/core:instance-parameter', GI_NAMESPACES) + instance_param = self._parse_parameter(child, True) + + children = node.findall('./core:parameters/core:parameter', GI_NAMESPACES) + params = [] + for child in children: + params.append(self._parse_parameter(child)) + - res = ast.Method(name=name, identifier=identifier, instance_param=instance_param, throws=throws) ++ res = ast.Method(name=name, identifier=identifier, instance_param=instance_param, throws=throws, ++ set_property=set_property, get_property=get_property) + res.set_return_value(return_value) + res.set_parameters(params) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_shadows(shadows) + res.set_shadowed_by(shadowed_by) + res.set_version(node.attrib.get('version')) + self._maybe_parse_docs(node, res) + return res + + def _parse_virtual_method(self, node: ET.Element) -> ast.VirtualMethod: + name = node.attrib.get('name') + identifier = node.attrib.get(_cns('identifier')) + invoker = node.attrib.get('invoker') + throws = node.attrib.get('throws', '0') == '1' + + child = node.find('core:return-value', GI_NAMESPACES) + return_value = self._parse_return_value(child) + + child = node.find('./core:parameters/core:instance-parameter', GI_NAMESPACES) + instance_param = self._parse_parameter(child, True) + + children = node.findall('./core:parameters/core:parameter', GI_NAMESPACES) + params = [] + for child in children: + params.append(self._parse_parameter(child)) + + res = ast.VirtualMethod(name=name, identifier=identifier, invoker=invoker, instance_param=instance_param, throws=throws) + res.set_return_value(return_value) + res.set_parameters(params) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_version(node.attrib.get('version')) + self._maybe_parse_docs(node, res) + return res + + def _parse_enum_member(self, node: ET.Element) -> ast.Member: + name = node.attrib.get('name') + value = node.attrib.get('value') + identifier = node.attrib.get(_cns("identifier")) + nick = node.attrib.get(_glibns("nick")) + + res = ast.Member(name=name, value=value, identifier=identifier, nick=nick) + self._maybe_parse_docs(node, res) + return res + + def _parse_enumeration(self, node: ET.Element, repo: ast.Repository, ns: ast.Namespace) -> None: + children = node.findall('core:member', GI_NAMESPACES) + if children is None or len(children) == 0: + return + + members = [] + for child in children: + members.append(self._parse_enum_member(child)) + + children = node.findall('core:function', GI_NAMESPACES) + functions = [] + for child in children: + functions.append(self._parse_type_function(child)) + + name: str = node.attrib['name'] + ctype: str = node.attrib[_cns('type')] + type_name: T.Optional[str] = node.attrib.get(_glibns('type-name')) + get_type: T.Optional[str] = node.attrib.get(_glibns('get-type')) + error_domain: T.Optional[str] = node.attrib.get(_glibns('error-domain')) + + gtype = None + if type_name is not None and get_type is not None: + gtype = ast.GType(type_name, get_type) + + if error_domain is not None: + res: ast.ErrorDomain = ast.ErrorDomain(name=name, namespace=ns.name, + ctype=ctype, gtype=gtype, + domain=error_domain) + ns.add_error_domain(res) + else: + res: ast.Enumeration = ast.Enumeration(name=name, namespace=ns.name, + ctype=ctype, gtype=gtype) + ns.add_enumeration(res) + + res.set_members(members) + res.set_functions(functions) + res.set_version(node.attrib.get('version')) + self._maybe_parse_docs(node, res) + + def _parse_bitfield(self, node: ET.Element, repo: ast.Repository, ns: ast.Namespace) -> None: + children = node.findall('core:member', GI_NAMESPACES) + if children is None or len(children) == 0: + return + + members = [] + for child in children: + members.append(self._parse_enum_member(child)) + + children = node.findall('core:function', GI_NAMESPACES) + functions = [] + for child in children: + functions.append(self._parse_type_function(child)) + + name = node.attrib.get('name') + ctype = node.attrib.get(_cns('type')) + type_name = node.attrib.get(_glibns('type-name')) + get_type = node.attrib.get(_glibns('get-type')) + + gtype = None + if type_name is not None: + gtype = ast.GType(type_name, get_type) + + res = ast.BitField(name=name, namespace=ns.name, ctype=ctype, gtype=gtype) + res.set_members(members) + res.set_functions(functions) + res.set_version(node.attrib.get('version')) + self._maybe_parse_docs(node, res) + ns.add_bitfield(res) + + def _parse_property(self, node: ET.Element) -> ast.Property: + name = node.attrib.get('name') + writable = node.attrib.get('writable', '0') == '1' + readable = node.attrib.get('readable', '1') == '1' + construct_only = node.attrib.get('construct-only', '0') == '1' + construct = node.attrib.get('construct', '0') == '1' + transfer = node.attrib.get('transfer-ownership') ++ setter = node.attrib.get('setter') ++ getter = node.attrib.get('getter') + + ctype = self._parse_ctype(node) + + res = ast.Property(name=name, transfer=transfer, target=ctype, + writable=writable, readable=readable, - construct=construct, construct_only=construct_only) ++ construct=construct, construct_only=construct_only, ++ setter=setter, getter=getter) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_version(node.attrib.get('version')) + self._maybe_parse_docs(node, res) + return res + + def _parse_signal(self, node: ET.Element) -> ast.Signal: + name = node.attrib.get('name') + when = node.attrib.get('when') + detailed = node.attrib.get('detailed') == '1' + action = node.attrib.get('action') == '1' + no_hooks = node.attrib.get('no-hooks') == '1' + no_recurse = node.attrib.get('no-recurse') == '1' + + child = node.find('core:return-value', GI_NAMESPACES) + return_value = None + if child is not None: + return_value = self._parse_return_value(child) + + children = node.findall('./core:parameters/core:parameter', GI_NAMESPACES) + params = [] + for child in children: + params.append(self._parse_parameter(child)) + + res = ast.Signal(name=name, when=when, detailed=detailed, action=action, no_hooks=no_hooks, no_recurse=no_recurse) + res.set_parameters(params) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_version(node.attrib.get('version')) + self._maybe_parse_docs(node, res) + if return_value is not None: + res.set_return_value(return_value) + return res + + def _parse_field(self, node: ET.Element) -> ast.Field: + name = node.attrib.get('name') + writable = node.attrib.get('writable', '0') == '1' + readable = node.attrib.get('readable', '0') == '1' + private = node.attrib.get('private', '0') == '1' + bits = int(node.attrib.get('bits', '0')) + + child = node.find('core:callback', GI_NAMESPACES) + if child is not None: + ctype = self._parse_callback_field(child) + else: + ctype = self._parse_ctype(node) + + if ctype is None: + ctype = ast.VoidType() + + res = ast.Field(name=name, writable=writable, readable=readable, private=private, bits=bits, target=ctype) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_version(node.attrib.get('version')) + self._maybe_parse_docs(node, res) + return res + + def _parse_implements(self, node: ET.Element) -> ast.Interface: + return self._lookup_type(name=node.attrib['name']) + + def _parse_class(self, node: ET.Element, repo: ast.Repository, ns: ast.Namespace) -> None: + name = node.attrib.get('name') + symbol_prefix = node.attrib.get(_cns('symbol-prefix')) + ctype = node.attrib.get(_cns('type')) + parent = node.attrib.get('parent') + type_name = node.attrib.get(_glibns('type-name')) + get_type = node.attrib.get(_glibns('get-type')) + type_struct = node.attrib.get(_glibns('type-struct')) + abstract = node.attrib.get('abstract', '0') == '1' + fundamental = node.attrib.get(_glibns('fundamental'), '0') == '1' + ref_func = node.attrib.get(_glibns('ref-func')) + unref_func = node.attrib.get(_glibns('unref-func')) + + parent_type = None + if parent is not None: + parent_type = self._lookup_type(name=parent) + + gtype = None + if type_name is not None: + gtype = ast.GType(type_name=type_name, get_type=get_type, type_struct=type_struct) + + fields = [] + children = node.findall('core:field', GI_NAMESPACES) + for child in children: + fields.append(self._parse_field(child)) + + ifaces = [] + children = node.findall('core:implements', GI_NAMESPACES) + for child in children: + ifaces.append(self._parse_implements(child)) + + ctors = [] + children = node.findall('core:constructor', GI_NAMESPACES) + for child in children: + ctors.append(self._parse_type_function(child)) + + methods = [] + children = node.findall('core:method', GI_NAMESPACES) + for child in children: + methods.append(self._parse_method(child)) + + vmethods = [] + children = node.findall('core:virtual-method', GI_NAMESPACES) + for child in children: + vmethods.append(self._parse_virtual_method(child)) + + functions = [] + children = node.findall('core:function', GI_NAMESPACES) + for child in children: + functions.append(self._parse_type_function(child)) + + properties = [] + children = node.findall('core:property', GI_NAMESPACES) + for child in children: + properties.append(self._parse_property(child)) + + signals = [] + children = node.findall('glib:signal', GI_NAMESPACES) + for child in children: + signals.append(self._parse_signal(child)) + + res = ast.Class(name=name, namespace=ns.name, symbol_prefix=symbol_prefix, ctype=ctype, + parent=parent_type, gtype=gtype, + abstract=abstract, fundamental=fundamental, + ref_func=ref_func, unref_func=unref_func) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_version(node.attrib.get('version')) + res.set_fields(fields) + res.set_implements(ifaces) + res.set_constructors(ctors) + res.set_methods(methods) + res.set_virtual_methods(vmethods) + res.set_functions(functions) + res.set_properties(properties) + res.set_signals(signals) + self._maybe_parse_docs(node, res) + ns.add_class(res) + + def _parse_interface(self, node: ET.Element, repo: ast.Repository, ns: ast.Namespace) -> None: + name = node.attrib.get('name') + symbol_prefix = node.attrib.get(_cns('symbol-prefix')) + ctype = node.attrib.get(_cns('type')) + type_name = node.attrib.get(_glibns('type-name')) + get_type = node.attrib.get(_glibns('get-type')) + type_struct = node.attrib.get(_glibns('type-struct')) + + gtype = None + if type_name is not None: + gtype = ast.GType(type_name=type_name, get_type=get_type, type_struct=type_struct) + + prerequisite = None + child = node.find('core:prerequisite', GI_NAMESPACES) + if child is not None: + prerequisite = self._lookup_type(name=child.attrib['name']) + + fields = [] + children = node.findall('core:field', GI_NAMESPACES) + for child in children: + fields.append(self._parse_field(child)) + + methods = [] + children = node.findall('core:method', GI_NAMESPACES) + for child in children: + methods.append(self._parse_method(child)) + + vmethods = [] + children = node.findall('core:virtual-method', GI_NAMESPACES) + for child in children: + vmethods.append(self._parse_virtual_method(child)) + + functions = [] + children = node.findall('core:function', GI_NAMESPACES) + for child in children: + functions.append(self._parse_type_function(child)) + + properties = [] + children = node.findall('core:property', GI_NAMESPACES) + for child in children: + properties.append(self._parse_property(child)) + + signals = [] + children = node.findall('glib:signal', GI_NAMESPACES) + for child in children: + signals.append(self._parse_signal(child)) + + res = ast.Interface(name=name, namespace=ns.name, symbol_prefix=symbol_prefix, ctype=ctype, gtype=gtype) + res.set_prerequisite(prerequisite) + res.set_fields(fields) + res.set_virtual_methods(vmethods) + res.set_properties(properties) + res.set_signals(signals) + res.set_methods(methods) + res.set_functions(functions) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_version(node.attrib.get('version')) + self._maybe_parse_docs(node, res) + ns.add_interface(res) + + def _parse_boxed(self, node: ET.Element, repo: ast.Repository, ns: ast.Namespace) -> None: + name = node.attrib.get(_glibns('name')) + symbol_prefix = node.attrib.get(_cns('symbol-prefix')) + type_name = node.attrib.get(_glibns('type-name')) + get_type = node.attrib.get(_glibns('get-type')) + + gtype = None + if type_name is not None: + gtype = ast.GType(type_name=type_name, get_type=get_type) + + functions = [] + children = node.findall('core:function', GI_NAMESPACES) + for child in children: + functions.append(self._parse_type_function(child)) + + res = ast.Boxed(name=name, namespace=ns.name, symbol_prefix=symbol_prefix, gtype=gtype) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_version(node.attrib.get('version')) + res.set_functions(functions) + self._maybe_parse_docs(node, res) + ns.add_boxed(res) + + def _parse_record(self, node: ET.Element, repo: ast.Repository, ns: ast.Namespace) -> None: + name: str = node.attrib['name'] + symbol_prefix: str = node.attrib.get(_cns('symbol-prefix'), '') + ctype: str = node.attrib[_cns('type')] + type_name: T.Optional[str] = node.attrib.get(_glibns('type-name')) + get_type: T.Optional[str] = node.attrib.get(_glibns('get-type')) + type_struct: T.Optional[str] = node.attrib.get(_glibns('type-struct')) + gtype_struct_for: T.Optional[str] = node.attrib.get(_glibns('is-gtype-struct-for')) + disguised: bool = node.attrib.get('disguised', '0') == '1' + + gtype = None + if type_name is not None: + gtype = ast.GType(type_name=type_name, get_type=get_type, type_struct=type_struct) + + fields = [] + children = node.findall('core:field', GI_NAMESPACES) + for child in children: + fields.append(self._parse_field(child)) + + ctors = [] + children = node.findall('core:constructor', GI_NAMESPACES) + for child in children: + ctors.append(self._parse_type_function(child)) + + methods = [] + children = node.findall('core:method', GI_NAMESPACES) + for child in children: + methods.append(self._parse_method(child)) + + functions = [] + children = node.findall('core:function', GI_NAMESPACES) + for child in children: + functions.append(self._parse_type_function(child)) + + res = ast.Record(name=name, namespace=ns.name, symbol_prefix=symbol_prefix, + ctype=ctype, gtype=gtype, + struct_for=gtype_struct_for, disguised=disguised) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_version(node.attrib.get('version')) + res.set_fields(fields) + res.set_constructors(ctors) + res.set_methods(methods) + res.set_functions(functions) + self._maybe_parse_docs(node, res) + ns.add_record(res) + + def _parse_union(self, node: ET.Element, repo: ast.Repository, ns: ast.Namespace) -> None: + name = node.attrib.get('name') + symbol_prefix = node.attrib.get(_cns('symbol-prefix')) + ctype = node.attrib.get(_cns('type')) + type_name = node.attrib.get(_glibns('type-name')) + get_type = node.attrib.get(_glibns('get-type')) + type_struct = node.attrib.get(_glibns('type-struct')) + + gtype = None + if type_name is not None: + gtype = ast.GType(type_name=type_name, get_type=get_type, type_struct=type_struct) + + fields = [] + children = node.findall('core:field', GI_NAMESPACES) + for child in children: + fields.append(self._parse_field(child)) + + ctors = [] + children = node.findall('core:constructor', GI_NAMESPACES) + for child in children: + ctors.append(self._parse_type_function(child)) + + methods = [] + children = node.findall('core:method', GI_NAMESPACES) + for child in children: + methods.append(self._parse_method(child)) + + functions = [] + children = node.findall('core:function', GI_NAMESPACES) + for child in children: + functions.append(self._parse_type_function(child)) + + res = ast.Union(name=name, namespace=ns.name, symbol_prefix=symbol_prefix, ctype=ctype, gtype=gtype) + res.set_introspectable(node.attrib.get('introspectable', '1') != '0') + res.set_version(node.attrib.get('version')) + res.set_fields(fields) + res.set_constructors(ctors) + res.set_methods(methods) + res.set_functions(functions) + self._maybe_parse_docs(node, res) + ns.add_union(res) diff --cc subprojects/gi-docgen/gidocgen/log.py index 9e4e4ccfe4,0000000000..e5a2262b4a mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/log.py +++ b/subprojects/gi-docgen/gidocgen/log.py @@@ -1,210 -1,0 +1,212 @@@ +# SPDX-FileCopyrightText: 2020 GNOME Foundation +# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +import os +import platform +import sys +import time + + +def setup_output(): + try: + if platform.system().lower() == 'windows': + return os.isatty(sys.stdout.fileno()) + return os.isatty(sys.stdout.fileno()) and os.environ.get('TERM') != 'dumb' + except Exception: + return False + + +def setup_debug(): + if os.environ.get('GIDOCGEN_DEBUG', '0') == '1': + return True + return False + + +log_colorize_output = setup_output() +log_debug = setup_debug() +log_quiet = False +log_fatal_warnings = False +log_warnings_counter = 0 +log_epoch = 0 + +colors = { + 'NONE': "[0m", + 'RED': "[1;31m", + 'GREEN': "[1;32m", + 'YELLOW': "[1;33m", + 'BLUE': "[1;34m", + 'LIGHT_GREY': "[1;37m", + 'DARK_GREY': "[1;90m", +} + +modifiers = { + 'NONE': "[0m", + 'DEFAULT': "[4;39m", + 'BOLD_DEFAULT': "[1;39m", + 'DIM_DEFAULT': "[2;39m", +} + + +logged_once = set() + + +class AnsiEscape(object): + ''' + A string-like object that contains an ANSI escaped string. + ''' + char = '\033' + + def __init__(self, *args, **kwargs): + self.text = kwargs.get('text', '') + self.color = kwargs.get('color', 'NONE') + self.mods = kwargs.get('mods', 'DEFAULT') + + def __str__(self): + if self.mods != 'DEFAULT': + return f'{AnsiEscape.char}{modifiers[self.mods]}{self.text}{AnsiEscape.char}{modifiers["NONE"]}' + return f'{AnsiEscape.char}{colors[self.color]}{self.text}{AnsiEscape.char}{colors["NONE"]}' + + +def color(text, color_id): + return f'\u001b[38;5;{color_id}m{text}\u001b[0m' + + +def red(text): + return AnsiEscape(text=text, color='RED') + + +def green(text): + return AnsiEscape(text=text, color='GREEN') + + +def yellow(text): + return AnsiEscape(text=text, color='YELLOW') + + +def blue(text): + return AnsiEscape(text=text, color='BLUE') + + +def bold(text): + return AnsiEscape(text=text, mods='BOLD_DEFAULT') + + +def dim(text): + return AnsiEscape(text=text, mods='DIM_DEFAULT') + + +class Location(object): + ''' + A location object, pointing to a filename and a line. + ''' + def __init__(self, **kwargs): + self.filename = kwargs.get('filename', 'input') + self.line = kwargs.get('line', 0) + + def __str__(self): + return f'{self.filename}:{self.line}:' + + +def log_once(text, prefix=None, location=None): + ''' + Prints a line of text only once. + ''' + t = tuple(text, prefix, location) + if t in logged_once: + return + log(text, prefix, location) + logged_once.add(t) + + +def set_quiet(quiet): + global log_quiet + log_quiet = quiet + + +def set_fatal_warnings(fatal_warnings): + global log_fatal_warnings + log_fatal_warnings = fatal_warnings + + +def set_log_epoch(epoch=0): + global log_epoch + if epoch == 0: + log_epoch = time.monotonic() + else: + log_epoch = epoch + + +def log(text, prefix=None, location=None, out=None): + ''' + Prints a line of text using the given prefix and location. + + @prefix: (optional): a prefix string, or an AnsiEscape object + @location: (optional): a location string, or a Location object + @out: (optional): a File object + ''' + res = [] + if prefix: + res += [str(prefix), ': '] + if location: + res += [str(location), ' '] + res += [text] + print(''.join(res), file=out) + + +def error(text, location=None): + '''Prints an error message''' + log(text, prefix=red('ERROR'), location=location, out=sys.stderr) + sys.exit(1) + + +def warning(text, location=None): + '''Prints a warning message''' + log(text, prefix=yellow('WARNING'), location=location, out=sys.stderr) + + global log_warnings_counter + log_warnings_counter += 1 + + if log_fatal_warnings: + sys.exit(1) + + +def info(text, location=None): + '''Prints an information message''' + if not log_quiet: + log(text, prefix=green('INFO'), location=location) + + +def debug(text, location=None): + '''Prints a debug message''' + if log_debug: + log(text, prefix=dim('DEBUG'), location=location) + + +def deprecation(text, location=None): + '''Prints a deprecation warning''' + log(text, prefix=blue('DEPRECATED'), location=location, out=sys.stderr) + global log_warnings_counter + log_warnings_counter += 1 + + +def checkpoint(prefix=None): + if log_quiet: + return + elapsed = (time.monotonic() - log_epoch) + msg = f"Elapsed time {elapsed:.3f} seconds" + if prefix is None: + prefix = green('INFO') + log(msg, prefix) + + +def report(): ++ global log_warnings_counter + if log_quiet: + return + elapsed = (time.monotonic() - log_epoch) + report = [""] + report += [f"Elapsed time: {elapsed:.3f} seconds"] + report += [f"Total warnings: {log_warnings_counter}"] - print("\n".join(report)) - return log_warnings_counter != 0 ++ if log_warnings_counter == 0: ++ return 0 ++ return 1 diff --cc subprojects/gi-docgen/gidocgen/mdext.py index 7ee1761c47,0000000000..5106871b07 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/mdext.py +++ b/subprojects/gi-docgen/gidocgen/mdext.py @@@ -1,53 -1,0 +1,68 @@@ +# SPDX-FileCopyrightText: 2021 GNOME Foundation +# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +from markdown.extensions import Extension +from markdown.preprocessors import Preprocessor + +import re + + +SIGNAL_SIGIL_RE = re.compile(r"(^|\W)#([A-Z][A-Za-z0-9]+)::([a-z0-9_-]+)\b") + +PROP_SIGIL_RE = re.compile(r"(^|\W)#([A-Z][A-Za-z0-9]+):([a-z0-9_-]+)\b") + +TYPE_SIGIL_RE = re.compile(r"(^|\W)#([A-Z][A-Za-z0-9]+)\b") + +ARG_SIGIL_RE = re.compile(r"(^|\W)@([A-Za-z0-9_]+)\b") + +CONST_SIGIL_RE = re.compile(r"(^|\W)%([A-Z0-9_]+)\b") + ++FUNCTION_RE = re.compile(r"(^|\s+)([a-z][a-z0-9_]*)\(\)(\s+|$)") ++ + +class GtkDocPreprocessor(Preprocessor): + """Remove all gtk-doc sigils from the Markdown text""" + def run(self, lines): + new_lines = [] ++ inside_code_block = False + for line in lines: ++ if line.startswith("```"): ++ if not inside_code_block: ++ inside_code_block = True ++ else: ++ inside_code_block = False ++ + new_line = line - # XXX: The order is important; signals and properties have - # higher precedence than types + - # Signal sigil - new_line = re.sub(SIGNAL_SIGIL_RE, r"\g<1>`\g<2>::\g<3>`", new_line) ++ # Never transform code blocks ++ if not inside_code_block: ++ # XXX: The order is important; signals and properties have ++ # higher precedence than types ++ ++ # Signal sigil ++ new_line = re.sub(SIGNAL_SIGIL_RE, r"\g<1>`\g<2>::\g<3>`", new_line) ++ ++ # Property sigil ++ new_line = re.sub(PROP_SIGIL_RE, r"\g<1>`\g<2>:\g<3>`", new_line) + - # Property sigil - new_line = re.sub(PROP_SIGIL_RE, r"\g<1>`\g<2>:\g<3>`", new_line) ++ # Type sigil ++ new_line = re.sub(TYPE_SIGIL_RE, r"\g<1>`\g<2>`", new_line) + - # Type sigil - new_line = re.sub(TYPE_SIGIL_RE, r"\g<1>`\g<2>`", new_line) ++ # Constant sygil ++ new_line = re.sub(CONST_SIGIL_RE, r"\g<1>`\g<2>`", new_line) + - # Constant sygil - new_line = re.sub(CONST_SIGIL_RE, r"\g<1>`\g<2>`", new_line) ++ # Argument sygil ++ new_line = re.sub(ARG_SIGIL_RE, r"\g<1>`\g<2>`", new_line) + - # Argument sygil - new_line = re.sub(ARG_SIGIL_RE, r"\g<1>`\g<2>`", new_line) ++ # Function ++ new_line = re.sub(FUNCTION_RE, r"\g<1>`\g<2>()`\g<3>", new_line) + + new_lines.append(new_line) + return new_lines + + +class GtkDocExtension(Extension): + """Markdown extension for gtk-doc""" + def extendMarkdown(self, md): + """Add extensions""" + md.preprocessors.register(GtkDocPreprocessor(md), 'gtkdoc', 27) diff --cc subprojects/gi-docgen/gidocgen/templates/basic/base.html index e353208ca2,0000000000..963a73e1e2 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/base.html +++ b/subprojects/gi-docgen/gidocgen/templates/basic/base.html @@@ -1,93 -1,0 +1,93 @@@ + + + + + + {% block title %}{{ namespace.name }}{% endblock %} + + + + + {% if CONFIG.site_url %} + + {% endif %} + + + {% if CONFIG.logo_url %} + + + + + {% endif %} + + {% block meta_other %}{% endblock %} + + {% if CONFIG.site_url %} + + {% endif %} + + + {% if CONFIG.site_url %} + + {% endif %} + + + + {% block style_other %}{% endblock %} + + {% if CONFIG.urlmap_file %} + + {% endif %} + {% if CONFIG.search_index %} + + + {% endif %} + + + + + +
    + + - - {% block navbar %} ++ + - {% endblock %} + + {% block content %}{% endblock %} + ++ {% block navbar %}{% endblock %} ++ + + +
    + {% block footer %}{% endblock %} +
    +
    + + diff --cc subprojects/gi-docgen/gidocgen/templates/basic/basic.toml index 15b6a7fb69,0000000000..3274d04755 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/basic.toml +++ b/subprojects/gi-docgen/gidocgen/templates/basic/basic.toml @@@ -1,75 -1,0 +1,76 @@@ +# SPDX-FileCopyrightText: 2021 GNOME Foundation +# +# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +[metadata] +name = "Basic" +author_name = "Emmanuele Bassi" +author_email = "ebassi@gnome.org" +copyright_year = "2021" +license = "Apache-2.0 OR GPL-3.0-or-later" + +[templates] +class = "class.html" +interface = "interface.html" +content = "content.html" +property = "property.html" +signal = "signal.html" +vfunc = "vfunc.html" +method = "method.html" +type_func = "type_func.html" +class_method = "class_method.html" +namespace = "namespace.html" +error = "enum.html" +flags = "enum.html" +enum = "enum.html" +constant = "constant.html" +record = "struct.html" +union = "struct.html" +alias = "struct.html" +function = "function.html" +ctor = "ctor.html" + +[css] +style = "style.css" + +[extra_files] +files = [ + "fonts.css", + "fzy.js", + "go-up-symbolic.png", + "main.js", - "pygment.css", ++ "solarized-light.css", ++ "solarized-dark.css", + "search.js", + "RedHatDisplay-Black.woff", + "RedHatDisplay-Black.woff2", + "RedHatDisplay-BlackItalic.woff", + "RedHatDisplay-BlackItalic.woff2", + "RedHatDisplay-Bold.woff", + "RedHatDisplay-Bold.woff2", + "RedHatDisplay-BoldItalic.woff", + "RedHatDisplay-BoldItalic.woff2", + "RedHatDisplay-Italic.woff", + "RedHatDisplay-Italic.woff2", + "RedHatDisplay-Medium.woff", + "RedHatDisplay-Medium.woff2", + "RedHatDisplay-MediumItalic.woff", + "RedHatDisplay-MediumItalic.woff2", + "RedHatDisplay-Regular.woff", + "RedHatDisplay-Regular.woff2", + "RedHatText-Bold.woff", + "RedHatText-Bold.woff2", + "RedHatText-BoldItalic.woff", + "RedHatText-BoldItalic.woff2", + "RedHatText-Italic.woff", + "RedHatText-Italic.woff2", + "RedHatText-Medium.woff", + "RedHatText-Medium.woff2", + "RedHatText-MediumItalic.woff", + "RedHatText-MediumItalic.woff2", + "RedHatText-Regular.woff", + "RedHatText-Regular.woff2", + "SourceCodePro-It.ttf.woff", + "SourceCodePro-Regular.ttf.woff", + "SourceCodePro-Semibold.ttf.woff", +] diff --cc subprojects/gi-docgen/gidocgen/templates/basic/class.html index 591fa79a76,0000000000..435f6e0fa9 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/class.html +++ b/subprojects/gi-docgen/gidocgen/templates/basic/class.html @@@ -1,591 -1,0 +1,677 @@@ + + +{% extends "base.html" %} + +{% block title %}{{ namespace.name }}.{{ class.name }}{% endblock %} + +{% block meta_other %} + + + + +{% endblock %} + +{% macro sidebar_block(elements, class_name, section_title, section_class, section_fragment) -%} +{% if elements|length > 0 %} +
    +
    {{ section_title }}
    + +
    +{% endif %} +{% endmacro %} + +{% block sidebar %} +
    +
    Type
    + +
    + +{{ sidebar_block(class.ctors, class.name, "Constructors", "ctor", "ctor") }} ++{{ sidebar_block(class.type_funcs, class.name, "Functions", "func", "type_func") }} +{{ sidebar_block(class.methods, class.name, "Instance methods", "method", "method") }} +{{ sidebar_block(class.properties, class.name, "Properties", "property", "property") }} +{{ sidebar_block(class.signals, class.name, "Signals", "signal", "signal") }} +{{ sidebar_block(class.class_methods, class.name, "Class methods", "method", "class_method") }} - {{ sidebar_block(class.type_funcs, class.name, "Functions", "func", "type_func") }} +{{ sidebar_block(class.virtual_methods, class.name, "Virtual methods", "method", "vfunc") }} +{% endblock %} + ++{% macro navbar_block(elements, section_title, section_link) -%} ++{% if elements|length > 0 %} ++
  • {{ section_title }}
  • ++{% endif %} ++{% endmacro %} ++ ++{% block navbar %} ++
    ++ ++
    ++{% endblock %} ++ +{% block content %} +
    +
    +

    Class

    +

    {{ namespace.name }}{{ class.name }}

    +
    + +
    + +
    +

    + Description + + {% if CONFIG.source_location_url and class.docs_location %} + [src] + {% endif %} +

    + +
    {{ class.c_decl }}
    + +
    + {{ class.description }} +
    + +
    + + {% if class.stability %} + + {% endif %} + {% if class.available_since %} + + {% endif %} + {% if class.deprecated_since %} + + + {% endif %} +
    Stability:{{ class.stability }}
    Available since:{{ class.available_since }}
    Deprecated since:{{ class.deprecated_since.version }}
    {{ class.deprecated_since.message }}
    +
    + + {% if class.attributes %} +
    + + {% for (key, value) in class.attributes.items() %} + + {% endfor %} +
    {{ key|escape }}{{ value|escape }}
    +
    + {% endif %} +
    +
    + + {% if CONFIG.show_class_hierarchy and (class.ancestors or class.interfaces) %} +
    +

    + Hierarchy + +

    +
    + {{ class.hierarchy_svg|safe }} +
    +
    + {% endif %} + + {% if class.ancestors %} +
    +

    + Ancestors + +

    + +
    + +
    +
    + {% endif %} + ++ {% if class.descendants %} ++
    ++

    Descendants

    ++
    ++
      ++ {%- for cls in class.descendants %} ++
    • {{ cls.ctype }}
    • ++ {% endfor -%} ++
    ++
    ++
    ++ {% endif %} ++ + {% if class.interfaces %} +
    +

    + Implements + +

    + +
    + +
    +
    + {% endif %} + + {% if class.ctors %} +
    +

    + Constructors + +

    + +
    + {% for ctor in class.ctors %} +
    +
    {{ ctor.identifier }}
    + +
    + {{ ctor.summary }} +
    + + {% if ctor.available_since or ctor.deprecated_since -%} +
    + {%- if ctor.available_since -%} +

    Available since: {{ ctor.available_since }}

    + {%- endif -%} + {%- if ctor.deprecated_since -%} +

    Deprecated since: {{ ctor.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} +
    + {% endfor %} +
    +
    + {% endif %} + - {% if class.methods %} ++ {% if class.type_funcs %} ++
    ++

    ++ Functions ++ ++

    ++ ++
    ++ {% for func in class.type_funcs %} ++
    ++
    {{ func.identifier }}
    ++ ++
    ++ {{ func.summary }} ++
    ++ ++ {% if func.available_since or func.deprecated_since -%} ++
    ++ {%- if func.available_since -%} ++

    Available since: {{ func.available_since }}

    ++ {%- endif -%} ++ {%- if func.deprecated_since -%} ++

    Deprecated since: {{ func.deprecated_since }}

    ++ {%- endif -%} ++
    ++ {%- endif %} ++
    ++ {% endfor %} ++
    ++
    ++ {% endif %} ++ ++ {% if class.show_methods %} +
    +

    + Instance methods + +

    + +
    + {% for method in class.methods %} +
    +
    {{ method.identifier }}
    +
    + {{ method.summary }} +
    + {% if method.available_since or method.deprecated_since -%} +
    + {%- if method.available_since -%} +

    Available since: {{ method.available_since }}

    + {%- endif -%} + {%- if method.deprecated_since -%} +

    Deprecated since: {{ method.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} +
    + {% endfor %} +
    + + {% for ancestor in class.ancestors %} - {% if ancestor.namespace == namespace.name and ancestor.n_methods > 0 %} ++ {% if ancestor.n_methods > 0 %} +
    ++ {%- if ancestor.namespace == namespace.name %} +
    Methods inherited from {{ ancestor.type_cname }} ({{ ancestor.n_methods }})
    ++ {%- else -%} ++
    Methods inherited from {{ ancestor.type_cname }} ({{ ancestor.n_methods }})
    ++ {% endif -%} + - {% if ancestor.methods %} +
    + {% for method in ancestor.methods %} ++ {%- if ancestor.namespace == namespace.name %} +
    {{ method.identifier }}
    ++ {%- else -%} ++
    {{ method.identifier }}
    ++ {% endif -%} +
    + {{ method.summary }} +
    + {% if method.available_since or method.deprecated_since -%} +
    + {%- if method.available_since -%} +

    Available since: {{ method.available_since }}

    + {%- endif -%} + {%- if method.deprecated_since -%} +

    Deprecated since: {{ method.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} + {% endfor %} +
    - {% endif %} +
    + {% endif %} + {% endfor %} + + {% for iface in class.interfaces %} - {% if iface.namespace == namespace.name and iface.n_methods > 0 %} ++ {% if iface.n_methods > 0 %} +
    ++ {%- if iface.namespace == namespace.name %} +
    Methods inherited from {{ iface.type_cname }} ({{ iface.n_methods }})
    ++ {%- else -%} ++
    Methods inherited from {{ iface.type_cname }} ({{ iface.n_methods }})
    ++ {% endif -%} + - {% if iface.methods %} +
    + {% for method in iface.methods %} ++ {%- if iface.namespace == namespace.name %} +
    {{ method.identifier }}
    ++ {%- else -%} ++
    {{ method.identifier }}
    ++ {% endif -%} +
    + {{ method.summary }} +
    + {% if method.available_since or method.deprecated_since -%} +
    + {%- if method.available_since -%} +

    Available since: {{ method.available_since }}

    + {%- endif -%} + {%- if method.deprecated_since -%} +

    Deprecated since: {{ method.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} + {% endfor %} +
    - {% endif %} +
    + {% endif %} + {% endfor %} +
    + {% endif %} + - {% if class.properties %} ++ {% if class.show_properties %} +
    +

    + Properties + +

    + ++ {% if class.properties %} +
    + {% for property in class.properties %} +
    +
    {{ class.fqtn }}:{{ property.name }}
    + +
    + {{ property.summary }} +
    + + {% if property.available_since or property.deprecated_since -%} +
    + {%- if property.available_since -%} +

    Available since: {{ property.available_since }}

    + {%- endif -%} + {%- if property.deprecated_since -%} +

    Deprecated since: {{ property.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} +
    + {% endfor %} +
    ++ {% endif %} + + {% for ancestor in class.ancestors %} - {% if ancestor.namespace == namespace.name and ancestor.n_properties > 0 %} ++ {% if ancestor.n_properties > 0 %} +
    ++ {%- if ancestor.namespace == namespace.name %} +
    Properties inherited from {{ ancestor.type_cname }} ({{ ancestor.n_properties }})
    ++ {%- else -%} ++
    Properties inherited from {{ ancestor.type_cname }} ({{ ancestor.n_properties }})
    ++ {% endif -%} + - {% if ancestor.properties %} +
    + {% for property in ancestor.properties %} ++ {%- if ancestor.namespace == namespace.name %} +
    {{ ancestor.fqtn }}:{{ property.name }}
    ++ {%- else -%} ++
    {{ ancestor.fqtn }}:{{ property.name }}
    ++ {% endif -%} +
    + {{ property.summary }} +
    + {% if property.available_since or property.deprecated_since -%} +
    + {%- if property.available_since -%} +

    Available since: {{ property.available_since }}

    + {%- endif -%} + {%- if property.deprecated_since -%} +

    Deprecated since: {{ property.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} + {% endfor %} +
    - {% endif %} +
    + {% endif %} + {% endfor %} + + {% for iface in class.interfaces %} - {% if iface.namespace == namespace.name and iface.n_properties > 0 %} ++ {% if iface.n_properties > 0 %} +
    ++ {%- if iface.namespace == namespace.name %} +
    Properties inherited from {{ iface.type_cname }} ({{ iface.n_properties }})
    ++ {%- else -%} ++
    Properties inherited from {{ iface.type_cname }} ({{ iface.n_properties }})
    ++ {% endif -%} + - {% if iface.properties %} +
    + {% for property in iface.properties %} ++ {%- if iface.namespace == namespace.name %} +
    {{ iface.fqtn }}:{{ property.name }}
    ++ {%- else -%} ++
    {{ iface.fqtn }}:{{ property.name }}
    ++ {% endif -%} +
    + {{ property.summary }} +
    + {% if property.available_since or property.deprecated_since -%} +
    + {%- if property.available_since -%} +

    Available since: {{ property.available_since }}

    + {%- endif -%} + {%- if property.deprecated_since -%} +

    Deprecated since: {{ property.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} + {% endfor %} +
    - {% endif %} +
    + {% endif %} + {% endfor %} + +
    + {% endif %} + - {% if class.signals %} ++ {% if class.show_signals %} +
    +

    + Signals + +

    + ++ {% if class.signals %} +
    + {% for signal in class.signals %} +
    +
    {{ class.fqtn }}::{{ signal.name }}
    +
    + {{ signal.summary }} +
    + {% if signal.available_since or signal.deprecated_since -%} +
    + {%- if signal.available_since -%} +

    Available since: {{ signal.available_since }}

    + {%- endif -%} + {%- if signal.deprecated_since -%} +

    Deprecated since: {{ signal.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} +
    + {% endfor %} +
    ++ {% endif %} + + {% for ancestor in class.ancestors %} - {% if ancestor.namespace == namespace.name and ancestor.n_signals > 0 %} ++ {% if ancestor.n_signals > 0 %} +
    ++ {%- if ancestor.namespace == namespace.name %} +
    Signals inherited from {{ ancestor.type_cname }} ({{ ancestor.n_signals }})
    ++ {%- else -%} ++
    Signals inherited from {{ ancestor.type_cname }} ({{ ancestor.n_signals }})
    ++ {% endif -%} + - {% if ancestor.signals %} +
    + {% for signal in ancestor.signals %} ++ {%- if ancestor.namespace == namespace.name %} +
    {{ ancestor.fqtn }}::{{ signal.name }}
    ++ {%- else -%} ++
    {{ ancestor.fqtn }}::{{ signal.name }}
    ++ {% endif -%} +
    + {{ signal.summary }} +
    + {% if signal.available_since or signal.deprecated_since -%} +
    + {%- if signal.available_since -%} +

    Available since: {{ signal.available_since }}

    + {%- endif -%} + {%- if signal.deprecated_since -%} +

    Deprecated since: {{ signal.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} + {% endfor %} +
    - {% endif %} +
    + {% endif %} + {% endfor %} + + {% for iface in class.interfaces %} - {% if iface.namespace == namespace.name and iface.n_signals %} ++ {% if iface.n_signals %} +
    ++ {%- if iface.namespace == namespace.name %} +
    Signals inherited from {{ iface.type_cname }} ({{ iface.n_signals }})
    ++ {%- else -%} ++
    Signals inherited from {{ iface.type_cname }} ({{ iface.n_signals }})
    ++ {% endif -%} + - {% if iface.signals %} +
    + {% for signal in iface.signals %} ++ {%- if iface.namespace == namespace.name %} +
    {{ iface.fqtn }}::{{ signal.name }}
    ++ {%- else -%} ++
    {{ iface.fqtn }}::{{ signal.name }}
    ++ {% endif -%} +
    + {{ signal.summary }} +
    + {% if signal.available_since or signal.deprecated_since -%} +
    + {%- if signal.available_since -%} +

    Available since: {{ signal.available_since }}

    + {%- endif -%} + {%- if signal.deprecated_since -%} +

    Deprecated since: {{ signal.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} + {% endfor %} +
    - {% endif %} +
    + {% endif %} + {% endfor %} + +
    + {% endif %} + + {% if class.class_name %} +
    +

    + Class structure + +

    + +
    +
    struct {{ namespace.name}}{{ class.class_name }} {
     +  {% for field in class.class_fields %}
     +  {%- if field.is_callback -%}
     +  {{ field.type_cname }};
     +  {%- else -%}
     +  {{ field.type_cname }} {{ field.name }};
     +  {%- endif %}
     +  {% else %}/* no available fields */{% endfor %}
     +}
    +
    + + {% if class.class_fields %} +
    +
    Class members
    + + + {% for field in class.class_fields %} + + + + + + + + + {% endfor %} +
    {{ field.name }}
    {{ field.type_cname }}
     {{ field.description }}
    +
    + {% endif %} +
    + {% endif %} + + {% if class.virtual_methods %} +
    +

    + Virtual methods + +

    + +
    + {% for method in class.virtual_methods %} +
    +
    {{ namespace.name }}.{{ class.class_name }}.{{ method.name }}
    + +
    + {{ method.summary }} +
    + + {% if method.available_since or method.deprecated_since -%} +
    + {%- if method.available_since -%} +

    Available since: {{ method.available_since }}

    + {%- endif -%} + {%- if method.deprecated_since -%} +

    Deprecated since: {{ method.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} +
    + {% endfor %} +
    +
    + {% endif %} + + {% if class.class_methods %} +
    +

    + Class methods + +

    + +
    + {% for method in class.class_methods %} +
    +
    {{ method.identifier }}
    + +
    + {{ method.summary }} +
    + + {% if method.available_since or method.deprecated_since -%} +
    + {%- if method.available_since -%} +

    Available since: {{ method.available_since }}

    + {%- endif -%} + {%- if method.deprecated_since -%} +

    Deprecated since: {{ method.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} +
    + {% endfor %} +
    +
    + {% endif %} + - {% if class.type_funcs %} -
    -

    - Functions - -

    - -
    - {% for func in class.type_funcs %} -
    -
    {{ func.identifier }}
    - -
    - {{ func.summary }} -
    - - {% if func.available_since or func.deprecated_since -%} -
    - {%- if func.available_since -%} -

    Available since: {{ func.available_since }}

    - {%- endif -%} - {%- if func.deprecated_since -%} -

    Deprecated since: {{ func.deprecated_since }}

    - {%- endif -%} -
    - {%- endif %} -
    - {% endfor %} -
    -
    - {% endif %} - +
    +
    +{% endblock %} diff --cc subprojects/gi-docgen/gidocgen/templates/basic/class_method.html index a26e93f72c,0000000000..51d11483ad mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/class_method.html +++ b/subprojects/gi-docgen/gidocgen/templates/basic/class_method.html @@@ -1,182 -1,0 +1,183 @@@ + + +{% extends "base.html" %} + +{% block title %}{{ namespace.name }}.{{ class.class_name }}.{{ class_method.name }}{% endblock %} + +{% block meta_other %} + + +{% endblock %} + +{% block sidebar %} +
    +
    Type
    + +
    +
    +
    Class methods
    + +
    +{% endblock %} + +{% block content %} +
    +
    +

    Class method

    +

    {{ namespace.name }}{{ class.class_name }}{{ class_method.name }}

    +
    + +
    +
    +

    + Declaration + + {% if CONFIG.source_location_url and class_method.source_location %} + [src] + {% endif %} +

    + +
    +
    {{ class_method.c_decl }}
    +
    +
    + +
    +

    + Description + + {% if CONFIG.source_location_url and class_method.docs_location %} + [src] + {% endif %} +

    + +
    + {{ class_method.description }} +
    + +
    + + {% if class_method.stability %} + + {% endif %} + {% if class_method.available_since %} + + {% endif %} + {% if class_method.deprecated_since %} + + + {% endif %} +
    Stability:{{ class_method.stability }}
    Available since:{{ class_method.available_since }}
    Deprecated since:{{ class_method.deprecated_since.version }}
    {{ class_method.deprecated_since.message }}
    +
    + + {% if class_method.attributes %} +
    + + {% for (key, value) in class_method.attributes.items() %} + + {% endfor %} +
    {{ key|escape }}{{ value|escape }}
    +
    + {% endif %} +
    + - {% if class_method.arguments|length > 1 %} ++ {% if class_method.arguments|length != 0 %} +
    +

    + Parameters + +

    + +
    + + {% for arg in class_method.arguments %} + + + + + + + + + {% if arg.direction != "in" %}{% endif %} + {% if arg.direction == "in" and arg.is_pointer and arg.nullable %}{% endif %} + {% if arg.direction == "out" and arg.is_pointer and arg.nullable %}{% endif %} + {% if arg.optional %}{% endif %} + {% if arg.is_array and arg.zero_terminated %}{% endif %} + {% if arg.is_array and arg.fixed_size > 0 %}{% endif %} + {% if arg.is_array and arg.len_arg %}{% endif %} + {% if arg.is_pointer %}{% endif %} + {% if arg.string_note %}{% endif %} + {% endfor %} + {% if class_method.throws %} + + + + + + + + + {% endif %} +
    {{ arg.name }} + {%- if arg.is_array -%}An array of {%- endif -%} + {%- if arg.is_list -%}A list of {%- endif -%} + {%- if arg.link -%} + {{ arg.link|safe }} + {%- else -%} + {{ arg.type_cname }} + {%- endif -%} +
     {{ arg.description|safe }}
     {{ arg.direction_note }}
     The argument can be NULL.
     The argument can be set to NULL.
     The argument can be NULL.
     The array must be NULL-terminated.
     The array must have {{ arg.fixed_size }} elements.
     The length of the array is specified in the {{ arg.len_arg }} argument.
     {{ arg.transfer_note }}
     {{ arg.string_note }}
    errorGError **
     The return location for a GError*, or NULL.
    +
    +
    + {% endif %} + + {% if class_method.return_value %} +
    +

    + Return value + +

    + +
    + + + + + + + + + + {% if class_method.return_value.is_array and class_method.return_value.zero_terminated %}{% endif %} + {% if class_method.return_value.is_array and class_method.return_value.fixed_size > 0 %}{% endif %} + {% if class_method.return_value.is_array and class_method.return_value.len_arg %}{% endif %} + {% if class_method.return_value.is_pointer %}{% endif %} + {% if class_method.return_value.is_pointer and class_method.return_value.nullable %}{% endif %} + {% if class_method.return_value.string_note %}{% endif %} +
    Returns: + {%- if class_method.return_value.is_array -%}An array of {%- endif -%} + {%- if class_method.return_value.is_list -%}A list of {%- endif -%} ++ {%- if class_method.return_value.is_list_model -%}A list model of {%- endif -%} + {%- if class_method.return_value.link -%} + {{ class_method.return_value.link|safe }} + {%- else -%} + {{ class_method.return_value.type_cname }} + {%- endif -%} +
     {{ class_method.return_value.description|safe }}
     The array is NULL-terminated.
     The array has {{ class_method.return_value.fixed_size }} elements.
     The length of the array is in the {{ class_method.return_value.len_arg }} argument.
     {{ class_method.return_value.transfer_note }}
     The return value can be NULL.
     {{ class_method.return_value.string_note }}
    +
    +
    + {% endif %} +
    +
    +{% endblock %} diff --cc subprojects/gi-docgen/gidocgen/templates/basic/enum.html index 081dece27b,0000000000..b92b6f14c9 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/enum.html +++ b/subprojects/gi-docgen/gidocgen/templates/basic/enum.html @@@ -1,171 -1,0 +1,189 @@@ + + +{% extends "base.html" %} + +{% block title %}{{ namespace.name }}.{{ enum.name }}{% endblock %} + +{% block meta_other %} + + + + +{% endblock %} + +{% macro sidebar_block(elements, enum_name, section_title, section_class, section_fragment) -%} +{% if elements|length > 0 %} +
    +
    {{ section_title }}
    + +
    +{% endif %} +{% endmacro %} + +{% block sidebar %} +
    +
    Type
    + +
    + +{{ sidebar_block(enum.type_funcs, enum.name, "Type functions", "func", "type_func") }} +{% endblock %} + ++{% macro navbar_block(elements, section_title, section_link) -%} ++{% if elements|length > 0 %} ++
  • {{ section_title }}
  • ++{% endif %} ++{% endmacro %} ++ ++{% block navbar %} ++
    ++ ++
    ++{% endblock %} ++ +{% block content %} +
    +
    +

    Enumeration

    +

    {{ namespace.name }}{{ enum.name }}

    +
    + +
    +
    +

    + Declaration + + {% if CONFIG.source_location_url and enum.source_location %} + [src] + {% endif %} +

    + +
    +
    {{ enum.c_decl }}
    +
    +
    + +
    +

    + Description + + {% if CONFIG.source_location_url and enum.docs_location %} + [src] + {% endif %} +

    + +
    + {{ enum.description }} +
    + +
    + + {% if enum.stability %} + + {% endif %} + {% if enum.available_since %} + + {% endif %} + {% if enum.deprecated_since %} + + + {% endif %} +
    Stability:{{ enum.stability }}
    Available since:{{ enum.available_since }}
    Deprecated since:{{ enum.deprecated_since.version }}
    {{ enum.deprecated_since.message }}
    +
    + + {% if enum.attributes %} +
    + + {% for (key, value) in enum.attributes.items() %} + + {% endfor %} +
    {{ key|escape }}{{ value|escape }}
    +
    + {% endif %} +
    + +
    +

    + Members + +

    + +
    + + + + + + {% for member in enum.members %} + + + + + {% endfor %} +
    NameDescription
    {{ member.name }}{{ member.description }}
    +
    +
    + + {% if enum.error_domain %} +
    +

    + Error domain + +

    + +
    +
    "{{ enum.domain }}"
    +
    +
    + {% endif %} + + {% if enum.type_funcs %} +
    +

    + Type functions + +

    + +
    + {% for func in enum.type_funcs %} +
    +
    {{ func.identifier }}
    + +
    + {{ func.summary }} +
    + + {% if func.available_since or func.deprecated_since -%} +
    + {%- if func.available_since -%} +

    Available since: {{ func.available_since }}

    + {%- endif -%} + {%- if func.deprecated_since -%} +

    Deprecated since: {{ func.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} +
    + {% endfor %} +
    + {% endif %} + +
    +
    +{% endblock %} diff --cc subprojects/gi-docgen/gidocgen/templates/basic/function.html index 5b19b74425,0000000000..4f8ffcf5b5 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/function.html +++ b/subprojects/gi-docgen/gidocgen/templates/basic/function.html @@@ -1,189 -1,0 +1,190 @@@ + + +{% extends "base.html" %} + +{% block title %}{{ namespace.name }}.{{ func.name }}{% endblock %} + +{% block meta_other %} + + + + +{% endblock %} + +{% block sidebar %} +{% if func.is_macro %} +
    +
    Function Macros
    + +
    +{% else %} +
    +
    Functions
    + +
    +{% endif %} +{% endblock %} + +{% block content %} +
    +
    +

    Function {% if func.is_macro %}Macro{% endif %}

    +

    {{ namespace.name }}{{ func.name }}

    +
    + +
    +
    +

    + Declaration + + {% if CONFIG.source_location_url and func.source_location %} + [src] + {% endif %} +

    + +
    +
    {{ func.c_decl }}
    +
    +
    + +
    +

    + Description + + {% if CONFIG.source_location_url and func.docs_location %} + [src] + {% endif %} +

    + +
    + {{ func.description }} +
    + +
    + + {% if func.stability %} + + {% endif %} + {% if func.available_since %} + + {% endif %} + {% if func.deprecated_since %} + + + {% endif %} +
    Stability:{{ func.stability }}
    Available since:{{ func.available_since }}
    Deprecated since:{{ func.deprecated_since.version }}
    {{ func.deprecated_since.message }}
    +
    + + {% if func.attributes %} +
    + + {% for (key, value) in func.attributes.items() %} + + {% endfor %} +
    {{ key|escape }}{{ value|escape }}
    +
    + {% endif %} +
    + + {% if func.arguments|length != 0 %} +
    +

    + Parameters + +

    + +
    + + {% for arg in func.arguments %} + + + + + + + + + {% if arg.direction != "in" %}{% endif %} + {% if arg.direction == "in" and arg.is_pointer and arg.nullable %}{% endif %} + {% if arg.direction == "out" and arg.is_pointer and arg.nullable %}{% endif %} + {% if arg.optional %}{% endif %} + {% if arg.is_array and arg.zero_terminated %}{% endif %} + {% if arg.is_array and arg.fixed_size > 0 %}{% endif %} + {% if arg.is_array and arg.len_arg %}{% endif %} + {% if arg.is_pointer %}{% endif %} + {% if arg.string_note %}{% endif %} + {% endfor %} + {% if func.throws %} + + + + + + + + + {% endif %} +
    {{ arg.name }} + {%- if arg.is_array -%}An array of {%- endif -%} + {%- if arg.is_list -%}A list of {%- endif -%} + {%- if arg.link -%} + {{ arg.link|safe }} + {%- else -%} + {{ arg.type_cname }} + {%- endif -%} +
     {{ arg.description|safe }}
     {{ arg.direction_note }}
     The argument can be NULL.
     The argument can be set to NULL.
     The argument can be NULL.
     The array must be NULL-terminated.
     The array must have {{ arg.fixed_size }} elements.
     The length of the array is specified in the {{ arg.len_arg }} argument.
     {{ arg.transfer_note }}
     {{ arg.string_note }}
    errorGError **
     The return location for a GError*, or NULL.
    +
    +
    + {% endif %} + + {% if func.return_value %} +
    +

    + Return value + +

    + +
    + + + + + + + + + + {% if func.return_value.is_array and func.return_value.zero_terminated %}{% endif %} + {% if func.return_value.is_array and func.return_value.fixed_size > 0 %}{% endif %} + {% if func.return_value.is_array and func.return_value.len_arg %}{% endif %} + {% if func.return_value.is_pointer %}{% endif %} + {% if func.return_value.is_pointer and func.return_value.nullable %}{% endif %} + {% if func.return_value.string_note %}{% endif %} +
    Returns: + {%- if func.return_value.is_array -%}An array of {%- endif -%} + {%- if func.return_value.is_list -%}A list of {%- endif -%} ++ {%- if func.return_value.is_list_model -%}A list model of {%- endif -%} + {%- if func.return_value.link -%} + {{ func.return_value.link|safe }} + {%- else -%} + {{ func.return_value.type_cname }} + {%- endif -%} +
     {{ func.return_value.description|safe }}
     The array is NULL-terminated.
     The array has {{ func.return_value.fixed_size }} elements.
     The length of the array is in the {{ func.return_value.len_arg }} argument.
     {{ func.return_value.transfer_note }}
     The return value can be NULL.
     {{ func.return_value.string_note }}
    +
    +
    + {% endif %} +
    +
    +{% endblock %} diff --cc subprojects/gi-docgen/gidocgen/templates/basic/interface.html index d61ac2d2be,0000000000..ea6f994393 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/interface.html +++ b/subprojects/gi-docgen/gidocgen/templates/basic/interface.html @@@ -1,315 -1,0 +1,368 @@@ + + +{% extends "base.html" %} + +{% block title %}{{ namespace.name }}.{{ interface.name }}{% endblock %} + +{% block meta_other %} + + + + +{% endblock %} + +{% macro sidebar_block(elements, iface_name, section_title, section_class, section_fragment) -%} +{% if elements|length > 0 %} +
    +
    {{ section_title }}
    + +
    +{% endif %} +{% endmacro %} + +{% block sidebar %} +
    +
    Type
    + +
    + ++{{ sidebar_block(interface.type_funcs, interface.name, "Functions", "func", "type_func") }} +{{ sidebar_block(interface.methods, interface.name, "Instance methods", "method", "method") }} +{{ sidebar_block(interface.properties, interface.name, "Properties", "property", "property") }} +{{ sidebar_block(interface.signals, interface.name, "Signals", "signal", "signal") }} +{{ sidebar_block(interface.class_methods, interface.name, "Interface methods", "method", "class_method") }} - {{ sidebar_block(interface.type_funcs, interface.name, "Functions", "func", "type_func") }} +{{ sidebar_block(interface.virtual_methods, interface.name, "Virtual methods", "method", "vfunc") }} +{% endblock %} + ++{% macro navbar_block(elements, section_title, section_link) -%} ++{% if elements|length > 0 %} ++
  • {{ section_title }}
  • ++{% endif %} ++{% endmacro %} ++ ++{% block navbar %} ++
    ++ ++
    ++{% endblock %} ++ +{% block content %} +
    +
    +

    Interface

    +

    {{ namespace.name }}{{ interface.name }}

    +
    + +
    + +
    +

    + Description + + {% if CONFIG.source_location_url and interface.docs_location %} + [src] + {% endif %} +

    + +
    {{ interface.c_decl }}
    + +
    + {{ interface.description }} +
    + +
    + + {% if interface.stability %} + + {% endif %} + {% if interface.available_since %} + + {% endif %} + {% if interface.deprecated_since %} + + + {% endif %} +
    Stability:{{ interface.stability }}
    Available since:{{ interface.available_since }}
    Deprecated since:{{ interface.deprecated_since.version }}
    {{ interface.deprecated_since.message }}
    +
    + + {% if interface.attributes %} +
    + + {% for (key, value) in interface.attributes.items() %} + + {% endfor %} +
    {{ key|escape }}{{ value|escape }}
    +
    + {% endif %} +
    +
    + ++
    ++

    ++ Prerequisite ++ ++

    ++ ++
    ++

    In order to implement {{ interface.name }}, your type must inherit from ++ {% if interface.requires_namespace == namespace.name -%} ++ ++ {%- else -%} ++ ++ {%- endif -%} ++ {{ interface.requires_ctype }}.

    ++
    ++
    ++ ++ {% if interface.implementations %} ++
    ++

    Implementations

    ++
    ++
      ++ {%- for impl in interface.implementations %} ++
    • {{ impl.ctype }}
    • ++ {% endfor -%} ++
    ++
    ++
    ++ {% endif %} ++ ++ {% if interface.type_funcs %} ++
    ++

    ++ Functions ++ ++

    ++ ++
    ++ {% for func in interface.type_funcs %} ++
    ++
    {{ func.identifier }}
    ++ ++
    ++ {{ func.summary }} ++
    ++ ++ {% if func.deprecated_since %} ++

    Deprecated since: {{ func.deprecated_since.version }}

    ++ {% endif %} ++
    ++ {% endfor %} ++
    ++
    ++ {% endif %} ++ + {% if interface.methods %} +
    +

    + Instance methods + +

    + +
    + {% for method in interface.methods %} +
    +
    {{ method.identifier }}
    + +
    + {{ method.summary }} +
    + + {% if method.available_since or method.deprecated_since -%} +
    + {%- if method.available_since -%} +

    Available since: {{ method.available_since }}

    + {%- endif -%} + {%- if method.deprecated_since -%} +

    Deprecated since: {{ method.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} +
    + {% endfor %} +
    + +
    + {% endif %} + + {% if interface.properties %} +
    +

    + Properties + +

    + +
    + {% for property in interface.properties %} +
    +
    {{ interface.fqtn }}:{{ property.name }}
    + +
    + {{ property.summary }} +
    + + {% if property.available_since or property.deprecated_since -%} +
    + {%- if property.available_since -%} +

    Available since: {{ property.available_since }}

    + {%- endif -%} + {%- if property.deprecated_since -%} +

    Deprecated since: {{ property.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} +
    + {% endfor %} +
    + +
    + {% endif %} + + {% if interface.signals %} +
    +

    + Signals + +

    + +
    + {% for signal in interface.signals %} +
    +
    {{ interface.fqtn }}::{{ signal.name }}
    + +
    + {{ signal.summary }} +
    + + {% if signal.available_since or signal.deprecated_since -%} +
    + {%- if signal.available_since -%} +

    Available since: {{ signal.available_since }}

    + {%- endif -%} + {%- if signal.deprecated_since -%} +

    Deprecated since: {{ signal.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} +
    + {% endfor %} - ++
    +
    + {% endif %} + + {% if interface.class_name %} +
    +

    + Interface structure + + {% if CONFIG.source_location_url and interface.source_location %} + [src] + {% endif %} +

    + +
    +
    struct {{ namespace.name}}{{ interface.class_name }} {
     +  {% for field in interface.class_fields %}
     +  {%- if field.is_callback -%}
     +  {{ field.type_cname }};
     +  {%- else -%}
     +  {{ field.type_cname }} {{ field.name }};
     +  {%- endif %}
     +  {% else %}/* no available fields */{% endfor %}
     +}
    +
    + + {% if interface.class_fields %} +
    +
    Interface members
    + + + {% for field in interface.class_fields %} + + + + + + + + {% endfor %} +
    {{ field.name }}
    {{ field.type_cname }}
     {{ field.description }}
    - {% endif %} +
    ++ {% endif %} +
    + {% endif %} + + {% if interface.class_methods %} +
    +

    + Interface methods + +

    + +
    + {% for method in interface.class_methods %} +
    +
    {{ method.identifier }}
    + +
    + {{ method.summary }} +
    + + {% if method.deprecated_since %} +

    Deprecated since: {{ method.deprecated_since.version }}

    + {% endif %} +
    + {% endfor %} +
    +
    + {% endif %} + - {% if interface.type_funcs %} -
    -

    - Functions - -

    - -
    - {% for func in interface.type_funcs %} -
    -
    {{ func.identifier }}
    - -
    - {{ func.summary }} -
    - - {% if func.deprecated_since %} -

    Deprecated since: {{ func.deprecated_since.version }}

    - {% endif %} -
    - {% endfor %} -
    -
    - {% endif %} - + {% if interface.virtual_methods %} +
    +

    + Virtual methods + +

    + +
    + {% for method in interface.virtual_methods %} +
    +
    {{ namespace.name }}.{{ interface.name }}.{{ method.name }}
    + +
    + {{ method.summary }} +
    + + {% if method.deprecated_since %} +

    Deprecated since: {{ method.deprecated_since.version }}

    + {% endif %} +
    + {% endfor %} +
    +
    + {% endif %} + +
    +
    +{% endblock %} diff --cc subprojects/gi-docgen/gidocgen/templates/basic/main.js index 7a3f45d72a,0000000000..09ee4806e2 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/main.js +++ b/subprojects/gi-docgen/gidocgen/templates/basic/main.js @@@ -1,172 -1,0 +1,176 @@@ +// SPDX-FileCopyrightText: 2021 GNOME Foundation +// +// SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later +"use strict"; + + +const urlMap = new Map(typeof baseURLs !== 'undefined' ? baseURLs : []); + +window.addEventListener("hashchange", onDidHashChange); +window.addEventListener("load", onDidLoad, false); +window.addEventListener("keydown", onKeyDown); + +function onDidLoad() { + attachScrollHandlers() + attachToggleHandlers() + attachCopyHandlers() + + if (window.onInitSearch) { + window.onInitSearch() + } +} + +function onDidHashChange() { + // When URL fragment changes to ID of a collapsible section, + // expand it when it is collapsed. + // This is useful for clicking section links in the sidebar on the index page. + const sectionHeader = document.querySelector(".section-header" + location.hash); + if (sectionHeader !== null) { + const parent = sectionHeader.parentNode; + if (hasClass(parent, "toggle-wrapper")) { + const toggle = parent.querySelector(".collapse-toggle"); + if (hasClass(toggle, "collapsed")) { + toggle.click(); + } + } + } +} + + +function attachScrollHandlers() { + const btnToTop = document.getElementById("btn-to-top"); + + btnToTop.addEventListener('click', onClick); + window.addEventListener('scroll', onScroll); + + function onClick(e) { + e.preventDefault(); + window.scroll({ top: 0, behavior: 'smooth' }); + } + + function onScroll() { + if (window.scrollY < 400) { + addClass(btnToTop, "hidden"); + } else { + removeClass(btnToTop, "hidden"); + } + } +} + +function attachToggleHandlers() { + function label(isCollapsed) { + return ( + "[" + + (isCollapsed ? "+" : "\u2212") + + "]" + ) + } + + function createToggle(isCollapsed) { + const toggle = document.createElement("a"); + toggle.href = "javascript:void(0)"; + toggle.className = "collapse-toggle"; + toggle.innerHTML = label(isCollapsed); + toggle.addEventListener('click', onClickToggle); + return toggle; + } + + function onClickToggle() { + if (hasClass(this, "collapsed")) { + removeClass(this, "collapsed"); + this.innerHTML = label(false); + forEach(this.parentNode.querySelectorAll(".docblock"), function(e) { + removeClass(e, "hidden"); + }); + } else { + addClass(this, "collapsed"); + this.innerHTML = label(true); + forEach(this.parentNode.querySelectorAll(".docblock"), function(e) { + addClass(e, "hidden"); + }); + } + } + + forEach(document.querySelectorAll(".toggle-wrapper"), function(e) { + const sectionHeader = e.querySelector(".section-header"); + const fragmentMatches = sectionHeader !== null && location.hash === "#" + sectionHeader.getAttribute('id'); + const collapsedByDefault = hasClass(e, "default-hide") && !fragmentMatches; + const toggle = createToggle(collapsedByDefault); + e.insertBefore(toggle, e.firstChild); + if (collapsedByDefault) { + addClass(toggle, "collapsed"); + forEach(e.querySelectorAll(".docblock"), function(d) { + addClass(d, "hidden"); + }); + } + }); + + function resolveNamespaceLink(namespace) { + return urlMap.get(namespace); + } + + forEach(document.querySelectorAll(".external"), function(e) { + if (e.tagName == "A" && e.dataset.hasOwnProperty('namespace')) { + var data_namespace = e.dataset.namespace + var data_link = e.dataset.link + var base_url = resolveNamespaceLink(data_namespace) + if (base_url !== undefined) { + e.href = base_url + data_link; + } else { + e.title = "No reference to the " + data_namespace + " namespace"; + } + } + }) +} + +function attachCopyHandlers() { + if (!navigator.clipboard) + return; + + forEach(document.querySelectorAll(".codehilite"), function(e) { + const button = document.createElement("button"); + button.className = "copy-button"; + button.innerText = "Copy"; + button.title = "Copy code to clipboard"; + + const text = e.innerText; + button.addEventListener("click", () => { + navigator.clipboard.writeText(text); + }); + + e.appendChild(button); + }) +} + +function onKeyDown(event) { + let search_input = document.querySelector("#search-input"); ++ // We don't want to try to focus the search input if it isn't visible. That way ++ // we avoid the preventDefault(), hence allowing devhelp to use S as mnemonic. ++ let potentially_hidden_parent = search_input.closest('.hidden, .devhelp-hidden'); + - if (event.code === "KeyS" && document.activeElement !== search_input) { ++ if (window.getComputedStyle(potentially_hidden_parent).display !== 'none' && ++ event.code === "KeyS" && document.activeElement !== search_input) { + event.preventDefault(); + search_input.focus(); + } +} + +// Helpers + +function hasClass(elem, className) { + return elem && elem.classList && elem.classList.contains(className); +} + +function addClass(elem, className) { + return elem && elem.classList && elem.classList.add(className); +} + +function removeClass(elem, className) { + return elem && elem.classList && elem.classList.remove(className); +} + +function forEach(arr, func) { + for (let i = 0; i < arr.length; ++i) { + func(arr[i]) + } +} diff --cc subprojects/gi-docgen/gidocgen/templates/basic/method.html index 49d1fe1ec5,0000000000..fc8e9c2c87 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/method.html +++ b/subprojects/gi-docgen/gidocgen/templates/basic/method.html @@@ -1,185 -1,0 +1,186 @@@ + + +{% extends "base.html" %} + +{% block title %}{{ namespace.name }}.{{ class.name }}.{{ method.name }}{% endblock %} + +{% block meta_other %} + + + + +{% endblock %} + +{% block sidebar %} +
    +
    Type
    + +
    +
    +
    Methods
    + +
    +{% endblock %} + +{% block content %} +
    +
    +

    Method

    +

    {{ namespace.name }}{{ class.name }}{{ method.name }}

    +
    + +
    +
    +

    + Declaration + + {% if CONFIG.source_location_url and method.source_location %} + [src] + {% endif %} +

    + +
    +
    {{ method.c_decl|safe }}
    +
    +
    + +
    +

    + Description + + {% if CONFIG.source_location_url and method.docs_location %} + [src] + {% endif %} +

    + +
    + {{ method.description|safe }} +
    + +
    + + {% if method.stability %} + + {% endif %} + {% if method.available_since %} + + {% endif %} + {% if method.deprecated_since %} + + + {% endif %} +
    Stability:{{ method.stability }}
    Available since:{{ method.available_since }}
    Deprecated since:{{ method.deprecated_since.version }}
    {{ method.deprecated_since.message|safe }}
    +
    + + {% if method.attributes %} +
    + + {% for (key, value) in method.attributes.items() %} + + {% endfor %} +
    {{ key|escape }}{{ value|escape }}
    +
    + {% endif %} +
    + + {% if method.arguments|length != 0 %} +
    +

    + Parameters + +

    + +
    + + {% for arg in method.arguments %} + + + + + + + + + {% if arg.direction != "in" %}{% endif %} + {% if arg.direction == "in" and arg.is_pointer and arg.nullable %}{% endif %} + {% if arg.direction == "out" and arg.is_pointer and arg.nullable %}{% endif %} + {% if arg.optional %}{% endif %} + {% if arg.is_array and arg.zero_terminated %}{% endif %} + {% if arg.is_array and arg.fixed_size > 0 %}{% endif %} + {% if arg.is_array and arg.len_arg %}{% endif %} + {% if arg.is_pointer %}{% endif %} + {% if arg.string_note %}{% endif %} + {% endfor %} + {% if method.throws %} + + + + + + + + + {% endif %} +
    {{ arg.name }} + {%- if arg.is_array -%}An array of {%- endif -%} + {%- if arg.is_list -%}A list of {%- endif -%} + {%- if arg.link -%} + {{ arg.link|safe }} + {%- else -%} + {{ arg.type_cname }} + {%- endif -%} +
     {{ arg.description|safe }}
     {{ arg.direction_note }}
     The argument can be NULL.
     The argument can be set to NULL.
     The argument can be NULL.
     The array must be NULL-terminated.
     The array must have {{ arg.fixed_size }} elements.
     The length of the array is specified in the {{ arg.len_arg }} argument.
     {{ arg.transfer_note }}
     {{ arg.string_note }}
    errorGError **
     The return location for a GError*, or NULL.
    +
    +
    + {% endif %} + + {% if method.return_value %} +
    +

    + Return value + +

    + +
    + + + + + + + + + + {% if method.return_value.is_array and method.return_value.zero_terminated %}{% endif %} + {% if method.return_value.is_array and method.return_value.fixed_size > 0 %}{% endif %} + {% if method.return_value.is_array and method.return_value.len_arg %}{% endif %} + {% if method.return_value.is_pointer %}{% endif %} + {% if method.return_value.is_pointer and method.return_value.nullable %}{% endif %} + {% if method.return_value.string_note %}{% endif %} +
    Returns: + {%- if method.return_value.is_array -%}An array of {%- endif -%} + {%- if method.return_value.is_list -%}A list of {%- endif -%} ++ {%- if method.return_value.is_list_model -%}A list model of {%- endif -%} + {%- if method.return_value.link -%} + {{ method.return_value.link|safe }} + {%- else -%} + {{ method.return_value.type_cname }} + {%- endif -%} +
     {{ method.return_value.description|safe }}
     The array is NULL-terminated.
     The array has {{ method.return_value.fixed_size }} elements.
     The length of the array is in the {{ method.return_value.len_arg }} argument.
     {{ method.return_value.transfer_note }}
     The return value can be NULL.
     {{ method.return_value.string_note }}
    +
    +
    + {% endif %} + +
    +
    +{% endblock %} diff --cc subprojects/gi-docgen/gidocgen/templates/basic/property.html index 0b2c6fc5db,0000000000..f4fd0080a2 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/property.html +++ b/subprojects/gi-docgen/gidocgen/templates/basic/property.html @@@ -1,120 -1,0 +1,122 @@@ + + +{% extends "base.html" %} + +{% block title %}{{ namespace.name }}.{{ class.name }}:{{ property.name }}{% endblock %} + +{% block meta_other %} + + + + +{% endblock %} + +{% block sidebar %} +
    +
    Type
    + +
    +
    +
    Properties
    + +
    +{% endblock %} + +{% block content %} +
    +
    +

    Property

    +

    {{ namespace.name }}{{ class.name }}:{{ property.name }}

    +
    + +
    +
    +

    + Declaration + +

    + +
    +
    {{ property.c_decl|safe }}
    +
    +
    + +
    +

    + Description + + {% if CONFIG.source_location_url and property.docs_location %} + [src] + {% endif %} +

    + +
    + {{ property.description }} +
    + +
    + + + + + {% if property.stability %} + + {% endif %} + {% if property.available_since %} + + {% endif %} + {% if property.deprecated_since %} + + + {% endif %} +
    Type: ++ {%- if property.is_array -%}An array of {%- endif -%} ++ {%- if property.is_list -%}A list of {%- endif -%} + {%- if property.link -%} + {{ property.link|safe }} + {%- else -%} + {{ property.type_cname }} + {%- endif -%} +
    Stability:{{ property.stability }}
    Available since:{{ property.available_since }}
    Deprecated since:{{ property.deprecated_since.version }}
    {{ property.deprecated_since.message }}
    +
    + + {% if property.attributes %} +
    + + {% for (key, value) in property.attributes.items() %} + + {% endfor %} +
    {{ key|escape }}{{ value|escape }}
    +
    + {% endif %} +
    + +
    +

    + Flags + +

    + +
    + + + + + +
    Readable{% if property.readable %}yes{% else %}no{% endif %}
    Writable{% if property.writable %}yes{% else %}no{% endif %}
    Construct{% if property.construct %}yes{% else %}no{% endif %}
    Construct only{% if property.construct_only %}yes{% else %}no{% endif %}
    +
    +
    + +
    +
    +{% endblock %} diff --cc subprojects/gi-docgen/gidocgen/templates/basic/search.js index 8913f6954c,0000000000..f635df656a mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/search.js +++ b/subprojects/gi-docgen/gidocgen/templates/basic/search.js @@@ -1,303 -1,0 +1,372 @@@ +// SPDX-FileCopyrightText: 2021 GNOME Foundation +// +// SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +(function() { + +const QUERY_TYPES = [ + "alias", + "bitfield", + "callback", + "class", + "constant", ++ "content", + "ctor", + "domain", + "enum", + "function_macro", + "function", + "interface", + "method", + "property", + "record", + "signal", + "type_func", + "union", + "vfunc", +]; +const QUERY_PATTERN = new RegExp("^(" + QUERY_TYPES.join('|') + ")\\s*:\\s*", 'i'); + + +const fzy = window.fzy; +const searchParams = getSearchParams(); +const refs = { + input: null, + form: null, + search: null, + main: null, ++ toc: null, +}; + +let searchIndex = undefined; +let searchResults = []; + +// Exports +window.onInitSearch = onInitSearch; + +/* Event handlers */ + +function onInitSearch() { + fetchJSON('index.json', onDidLoadSearchIndex); +} + +function onDidLoadSearchIndex(data) { + searchIndex = new SearchIndex(data) + - refs.input = document.querySelector("#search-input") - refs.form = document.querySelector("#search-form") - refs.search = document.querySelector("#search") - refs.main = document.querySelector("#main") ++ refs.input = document.querySelector("#search-input"); ++ refs.form = document.querySelector("#search-form"); ++ refs.search = document.querySelector("#search"); ++ refs.main = document.querySelector("#main"); ++ refs.toc = document.querySelector("#toc"); + - attachInputHandlers() ++ attachInputHandlers(); + + if (searchParams.q) { + search(searchParams.q); + } +} + ++function getNakedUrl() { ++ return window.location.href.split("?")[0].split("#")[0]; ++} ++ +function onDidSearch() { - const query = refs.input.value - if (query) - search(query) - else - hideSearchResults() ++ const query = refs.input.value; ++ if (query) { ++ search(query); ++ } ++ else { ++ hideSearchResults(); ++ } +} + +function onDidSubmit(ev) { + ev.preventDefault(); - if (searchResults.length > 0) { - window.location.href = searchResults[0].href ++ if (searchResults.length == 1) { ++ window.location.href = searchResults[0].href; + } +} + +function attachInputHandlers() { + if (refs.input.value === "") { + refs.input.value === searchParams.q || ""; + } + - refs.input.addEventListener('keydown', debounce(200, onDidSearch)) ++ refs.input.addEventListener('keyup', debounce(500, onDidSearch)) + refs.form.addEventListener('submit', onDidSubmit) +} + +/* Searching */ + +function searchQuery(query) { + const q = matchQuery(query); + const docs = searchIndex.searchDocs(q.term, q.type); + + const results = docs.map(function(doc) { + return { + name: doc.name, + type: doc.type, - text: getTextForDocument(doc, searchIndex.meta), ++ text: getLabelForDocument(doc, searchIndex.meta), + href: getLinkForDocument(doc), + summary: doc.summary, + }; + }); + + return results; +} + +function search(query) { + searchResults = searchQuery(query) + showResults(query, searchResults); +} + +/* Rendering */ + +function showSearchResults() { + addClass(refs.main, "hidden"); ++ if (refs.toc) { ++ addClass(refs.toc, "hidden"); ++ } + removeClass(refs.search, "hidden"); +} + +function hideSearchResults() { + addClass(refs.search, "hidden"); + removeClass(refs.main, "hidden"); ++ if (refs.toc) { ++ removeClass(refs.toc, "hidden"); ++ } +} + +function renderResults(query, results) { + let html = ""; + + html += "

    Results for "" + query + "" (" + results.length + ")

    " + + "
    " + + if (results.length === 0) { + html += "No results found."; + } + else { + html += "" + + ""; + results.forEach(function(item) { + html += "" + + "" + + "" + + ""; + }); + html += "
    NameDescription
    " + - "" + item.text + "" + ++ "" + item.text + "" + + "" + item.summary + "
    "; + } + + html += "
    "; + + return html; +} + +function showResults(query, results) { ++ if (window.history && typeof window.history.pushState === "function") { ++ let baseUrl = getNakedUrl(); ++ let extra = "?q=" + encodeURIComponent(refs.input.value); ++ window.history.replaceState(refs.input.value, "", baseUrl + extra + window.location.hash); ++ } ++ + window.title = "Results for: " + query; + window.scroll({ top: 0 }) + refs.search.innerHTML = renderResults(query, results); + showSearchResults(search); +} + + +/* Search data instance */ + +function SearchIndex(searchIndex) { + this.symbols = searchIndex.symbols; + this.meta = searchIndex.meta; +} +SearchIndex.prototype.searchDocs = function searchDocs(term, type) { + const filteredSymbols = !type ? + this.symbols : + this.symbols.filter(s => s.type === type); + const results = fzy.filter(term, filteredSymbols, doc => getTextForDocument(doc, this.meta)) + return results.map(i => i.item) +} + + +/* Search metadata selectors */ + +function getLinkForDocument(doc) { + switch (doc.type) { + case "alias": return "alias." + doc.name + ".html"; + case "bitfield": return "flags." + doc.name + ".html"; + case "callback": return "callback." + doc.name + ".html"; + case "class": return "class." + doc.name + ".html"; - case "class_method": return "class_method." + doc.type_name + "." + doc.name + ".html"; ++ case "class_method": return "class_method." + doc.struct_for + "." + doc.name + ".html"; + case "constant": return "const." + doc.name + ".html"; ++ case "content": return doc.href; + case "ctor": return "ctor." + doc.type_name + "." + doc.name + ".html"; + case "domain": return "error." + doc.name + ".html"; + case "enum": return "enum." + doc.name + ".html"; + case "function": return "func." + doc.name + ".html"; + case "function_macro": return "func." + doc.name + ".html"; + case "interface": return "iface." + doc.name + ".html"; + case "method": return "method." + doc.type_name + "." + doc.name + ".html"; + case "property": return "property." + doc.type_name + "." + doc.name + ".html"; + case "record": return "struct." + doc.name + ".html"; + case "signal": return "signal." + doc.type_name + "." + doc.name + ".html"; + case "type_func": return "type_func." + doc.type_name + "." + doc.name + ".html"; + case "union": return "union." + doc.name + ".html"; + case "vfunc": return "vfunc." + doc.type_name + "." + doc.name + ".html"; + } + return null; +} + ++function getLabelForDocument(doc, meta) { ++ switch (doc.type) { ++ case "alias": ++ case "bitfield": ++ case "callback": ++ case "class": ++ case "domain": ++ case "enum": ++ case "interface": ++ case "record": ++ case "union": ++ return "" + doc.ctype + ""; ++ ++ case "class_method": ++ case "constant": ++ case "ctor": ++ case "function": ++ case "function_macro": ++ case "method": ++ case "type_func": ++ return "" + doc.ident + ""; ++ ++ // NOTE: meta.ns added for more consistent results, otherwise ++ // searching for "Button" would return all signals, properties ++ // and vfuncs (eg "Button.clicked") before the actual object ++ // (eg "GtkButton") because "Button" matches higher with starting ++ // sequences. ++ case "property": ++ return "" + meta.ns + doc.type_name + ":" + doc.name + ""; ++ case "signal": ++ return "" + meta.ns + doc.type_name + "::" + doc.name + ""; ++ case "vfunc": ++ return "" + meta.ns + doc.type_name + "." + doc.name + ""; ++ ++ case "content": ++ return doc.name; ++ } ++ ++ return null; ++} ++ +function getTextForDocument(doc, meta) { + switch (doc.type) { + case "alias": + case "bitfield": ++ case "callback": + case "class": + case "domain": + case "enum": + case "interface": + case "record": + case "union": + return doc.ctype; ++ + case "class_method": + case "constant": + case "ctor": + case "function": + case "function_macro": + case "method": + case "type_func": + return doc.ident; + + // NOTE: meta.ns added for more consistent results, otherwise + // searching for "Button" would return all signals, properties + // and vfuncs (eg "Button.clicked") before the actual object + // (eg "GtkButton") because "Button" matches higher with starting + // sequences. + case "property": + return meta.ns + doc.type_name + ":" + doc.name; + case "signal": + return meta.ns + doc.type_name + "::" + doc.name; + case "vfunc": + return meta.ns + doc.type_name + "." + doc.name; + - case "callback": ++ case "content": + return doc.name; + } + + return null; +} + + +// Helpers + +function fetchJSON(url, callback) { + const request = new XMLHttpRequest(); + request.open('GET', url, true); + request.onreadystatechange = function() { + if (request.readyState === XMLHttpRequest.DONE) { + const status = request.status; + + if (status === 0 || (status >= 200 && status < 400)) { + callback(JSON.parse(request.responseText)); + } + } + } + request.send(null); +} + +function getSearchParams() { + const params = {}; + window.location.search.substring(1).split('&') + .map(function(s) { + const pair = s.split('='); + params[decodeURIComponent(pair[0])] = + typeof pair[1] === 'undefined' ? null : decodeURIComponent(pair[1].replace(/\+/g, '%20')); + }); + return params; +} + +function matchQuery(input) { + let type = null + let term = input + + const matches = term.match(QUERY_PATTERN); + if (matches) { + type = matches[1]; + term = term.substring(matches[0].length); + } + + // Remove all spaces, fzy will handle things gracefully. + term = term.replace(/\s+/g, '') + + return { type: type, term: term } +} + +function debounce(delay, fn) { - let timeout - let savedArgs - return function() { - const self = this - savedArgs = Array.prototype.slice.call(arguments) - if (timeout) - clearTimeout(timeout) - timeout = setTimeout(function() { - fn.apply(self, savedArgs) - timeout = undefined - }, delay) - } ++ let timeout; ++ let savedArgs ++ ++ return function() { ++ const self = this; ++ savedArgs = Array.prototype.slice.call(arguments); ++ ++ if (timeout) { ++ clearTimeout(timeout); ++ } ++ ++ timeout = setTimeout(function() { ++ fn.apply(self, savedArgs) ++ timeout = undefined ++ }, delay) ++ } +} + +})() diff --cc subprojects/gi-docgen/gidocgen/templates/basic/signal.html index ea27925f1a,0000000000..68ef3f87ad mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/signal.html +++ b/subprojects/gi-docgen/gidocgen/templates/basic/signal.html @@@ -1,195 -1,0 +1,196 @@@ + + +{% extends "base.html" %} + +{% block title %}{{ namespace.name }}.{{ class.name }}::{{ signal.name }}{% endblock %} + +{% block meta_other %} + + + + +{% endblock %} + +{% block sidebar %} +
    +
    Type
    + +
    +
    +
    Signals
    + +
    +{% endblock %} + +{% block content %} +
    +
    +

    Signal

    +

    {{ namespace.name }}{{ class.name }}::{{ signal.name }}

    +
    + +
    +
    +

    + Declaration + +

    + +
    +
    {{ signal.c_decl }}
    +
    +
    + +
    +

    + Description + + {% if CONFIG.source_location_url and signal.docs_location %} + [src] + {% endif %} +

    + +
    + {{ signal.description }} +
    + +
    + + + {% if signal.no_recurse %} + + {% endif %} + {% if signal.is_action %} + + {% endif %} + {% if signal.is_detailed %} + + {% endif %} + {% if signal.no_hooks %} + + {% endif %} + {% if signal.stability %} + + {% endif %} + {% if signal.available_since %} + + {% endif %} + {% if signal.deprecated_since %} + + + {% endif %} +
    Default handler: {{ signal.when }}
    Signal emission will restart instead of recursing
    The signal can be emitted directly
    The signal can be detailed
    Hooks are disabled for this signal
    Stability:{{ signal.stability }}
    Available since:{{ signal.available_since }}
    Deprecated since:{{ signal.deprecated_since.version }}
    {{ signal.deprecated_since.message }}
    +
    + + {% if signal.attributes %} +
    + + {% for (key, value) in signal.attributes.items() %} + + {% endfor %} +
    {{ key|escape }}{{ value|escape }}
    +
    + {% endif %} +
    + + {% if signal.arguments|length != 0 %} +
    +

    + Parameters + +

    + +
    + + {% for arg in signal.arguments %} + + + + + + + + + {% if arg.direction != "in" %}{% endif %} + {% if arg.direction == "in" and arg.is_pointer and arg.nullable %}{% endif %} + {% if arg.direction == "out" and arg.is_pointer and arg.nullable %}{% endif %} + {% if arg.optional %}{% endif %} + {% if arg.is_array and arg.zero_terminated %}{% endif %} + {% if arg.is_array and arg.fixed_size > 0 %}{% endif %} + {% if arg.is_array and arg.len_arg %}{% endif %} + {% if arg.is_pointer %}{% endif %} + {% if arg.string_note %}{% endif %} + {% endfor %} + {% if signal.throws %} + + + + + + + + + {% endif %} +
    {{ arg.name }} + {%- if arg.is_array -%}An array of {%- endif -%} + {%- if arg.is_list -%}A list of {%- endif -%} + {%- if arg.link -%} + {{ arg.link|safe }} + {%- else -%} + {{ arg.type_cname }} + {%- endif -%} +
     {{ arg.description|safe }}
     {{ arg.direction_note }}
     The argument can be NULL.
     The argument can be set to NULL.
     The argument can be NULL.
     The array must be NULL-terminated.
     The array must have {{ arg.fixed_size }} elements.
     The length of the array is specified in the {{ arg.len_arg }} argument.
     {{ arg.transfer_note }}
     {{ arg.string_note }}
    errorGError **
     The return location for a GError*, or NULL.
    +
    +
    + {% endif %} + + {% if signal.return_value %} +
    +

    + Return value + +

    + +
    + + + + + + + + + + {% if signal.return_value.is_array and signal.return_value.zero_terminated %}{% endif %} + {% if signal.return_value.is_array and signal.return_value.fixed_size > 0 %}{% endif %} + {% if signal.return_value.is_array and signal.return_value.len_arg %}{% endif %} + {% if signal.return_value.is_pointer %}{% endif %} + {% if signal.return_value.is_pointer and signal.return_value.nullable %}{% endif %} + {% if signal.return_value.string_note %}{% endif %} +
    Returns: + {%- if signal.return_value.is_array -%}An array of {%- endif -%} + {%- if signal.return_value.is_list -%}A list of {%- endif -%} ++ {%- if signal.return_value.is_list_model -%}A list model of {%- endif -%} + {%- if signal.return_value.link -%} + {{ signal.return_value.link|safe }} + {%- else -%} + {{ signal.return_value.type_cname }} + {%- endif -%} +
     {{ signal.return_value.description|safe }}
     The array is NULL-terminated.
     The array has {{ signal.return_value.fixed_size }} elements.
     The length of the array is in the {{ signal.return_value.len_arg }} argument.
     {{ signal.return_value.transfer_note }}
     The return value can be NULL.
     {{ signal.return_value.string_note }}
    +
    +
    + {% endif %} + +
    +
    +{% endblock %} diff --cc subprojects/gi-docgen/gidocgen/templates/basic/solarized-dark.css index 0000000000,0000000000..2edc59b884 new file mode 100644 --- /dev/null +++ b/subprojects/gi-docgen/gidocgen/templates/basic/solarized-dark.css @@@ -1,0 -1,0 +1,88 @@@ ++/* ++ * SPDX-FileCopyrightText: 2014 John Louis Del Rosario, Hank Gay, John Mastro, Brandon Bennett ++ * SPDX-License-Identifier: MIT ++ */ ++ ++pre { line-height: 125%; } ++td.linenos pre { color: #586e75; background-color: #073642; padding-left: 5px; padding-right: 5px; } ++span.linenos { color: #586e75; background-color: #073642; padding-left: 5px; padding-right: 5px; } ++td.linenos pre.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } ++span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } ++.codehilite .hll { background-color: #073642 } ++.codehilite { background: #002b36; color: #839496 } ++.codehilite .c { color: #586e75; font-style: italic } /* Comment */ ++.codehilite .err { color: #839496; background-color: #dc322f } /* Error */ ++.codehilite .esc { color: #839496 } /* Escape */ ++.codehilite .g { color: #839496 } /* Generic */ ++.codehilite .k { color: #859900 } /* Keyword */ ++.codehilite .l { color: #839496 } /* Literal */ ++.codehilite .n { color: #839496 } /* Name */ ++.codehilite .o { color: #586e75 } /* Operator */ ++.codehilite .x { color: #839496 } /* Other */ ++.codehilite .p { color: #839496 } /* Punctuation */ ++.codehilite .ch { color: #586e75; font-style: italic } /* Comment.Hashbang */ ++.codehilite .cm { color: #586e75; font-style: italic } /* Comment.Multiline */ ++.codehilite .cp { color: #d33682 } /* Comment.Preproc */ ++.codehilite .cpf { color: #586e75 } /* Comment.PreprocFile */ ++.codehilite .c1 { color: #586e75; font-style: italic } /* Comment.Single */ ++.codehilite .cs { color: #586e75; font-style: italic } /* Comment.Special */ ++.codehilite .gd { color: #dc322f } /* Generic.Deleted */ ++.codehilite .ge { color: #839496; font-style: italic } /* Generic.Emph */ ++.codehilite .gr { color: #dc322f } /* Generic.Error */ ++.codehilite .gh { color: #839496; font-weight: bold } /* Generic.Heading */ ++.codehilite .gi { color: #859900 } /* Generic.Inserted */ ++.codehilite .go { color: #839496 } /* Generic.Output */ ++.codehilite .gp { color: #839496 } /* Generic.Prompt */ ++.codehilite .gs { color: #839496; font-weight: bold } /* Generic.Strong */ ++.codehilite .gu { color: #839496; text-decoration: underline } /* Generic.Subheading */ ++.codehilite .gt { color: #268bd2 } /* Generic.Traceback */ ++.codehilite .kc { color: #2aa198 } /* Keyword.Constant */ ++.codehilite .kd { color: #2aa198 } /* Keyword.Declaration */ ++.codehilite .kn { color: #cb4b16 } /* Keyword.Namespace */ ++.codehilite .kp { color: #859900 } /* Keyword.Pseudo */ ++.codehilite .kr { color: #859900 } /* Keyword.Reserved */ ++.codehilite .kt { color: #b58900 } /* Keyword.Type */ ++.codehilite .ld { color: #839496 } /* Literal.Date */ ++.codehilite .m { color: #2aa198 } /* Literal.Number */ ++.codehilite .s { color: #2aa198 } /* Literal.String */ ++.codehilite .na { color: #839496 } /* Name.Attribute */ ++.codehilite .nb { color: #268bd2 } /* Name.Builtin */ ++.codehilite .nc { color: #268bd2 } /* Name.Class */ ++.codehilite .no { color: #268bd2 } /* Name.Constant */ ++.codehilite .nd { color: #268bd2 } /* Name.Decorator */ ++.codehilite .ni { color: #268bd2 } /* Name.Entity */ ++.codehilite .ne { color: #268bd2 } /* Name.Exception */ ++.codehilite .nf { color: #268bd2 } /* Name.Function */ ++.codehilite .nl { color: #268bd2 } /* Name.Label */ ++.codehilite .nn { color: #268bd2 } /* Name.Namespace */ ++.codehilite .nx { color: #839496 } /* Name.Other */ ++.codehilite .py { color: #839496 } /* Name.Property */ ++.codehilite .nt { color: #268bd2 } /* Name.Tag */ ++.codehilite .nv { color: #268bd2 } /* Name.Variable */ ++.codehilite .ow { color: #859900 } /* Operator.Word */ ++.codehilite .w { color: #839496 } /* Text.Whitespace */ ++.codehilite .mb { color: #2aa198 } /* Literal.Number.Bin */ ++.codehilite .mf { color: #2aa198 } /* Literal.Number.Float */ ++.codehilite .mh { color: #2aa198 } /* Literal.Number.Hex */ ++.codehilite .mi { color: #2aa198 } /* Literal.Number.Integer */ ++.codehilite .mo { color: #2aa198 } /* Literal.Number.Oct */ ++.codehilite .sa { color: #2aa198 } /* Literal.String.Affix */ ++.codehilite .sb { color: #2aa198 } /* Literal.String.Backtick */ ++.codehilite .sc { color: #2aa198 } /* Literal.String.Char */ ++.codehilite .dl { color: #2aa198 } /* Literal.String.Delimiter */ ++.codehilite .sd { color: #586e75 } /* Literal.String.Doc */ ++.codehilite .s2 { color: #2aa198 } /* Literal.String.Double */ ++.codehilite .se { color: #2aa198 } /* Literal.String.Escape */ ++.codehilite .sh { color: #2aa198 } /* Literal.String.Heredoc */ ++.codehilite .si { color: #2aa198 } /* Literal.String.Interpol */ ++.codehilite .sx { color: #2aa198 } /* Literal.String.Other */ ++.codehilite .sr { color: #cb4b16 } /* Literal.String.Regex */ ++.codehilite .s1 { color: #2aa198 } /* Literal.String.Single */ ++.codehilite .ss { color: #2aa198 } /* Literal.String.Symbol */ ++.codehilite .bp { color: #268bd2 } /* Name.Builtin.Pseudo */ ++.codehilite .fm { color: #268bd2 } /* Name.Function.Magic */ ++.codehilite .vc { color: #268bd2 } /* Name.Variable.Class */ ++.codehilite .vg { color: #268bd2 } /* Name.Variable.Global */ ++.codehilite .vi { color: #268bd2 } /* Name.Variable.Instance */ ++.codehilite .vm { color: #268bd2 } /* Name.Variable.Magic */ ++.codehilite .il { color: #2aa198 } /* Literal.Number.Integer.Long */ diff --cc subprojects/gi-docgen/gidocgen/templates/basic/solarized-light.css index 0000000000,0000000000..f1fa80f737 new file mode 100644 --- /dev/null +++ b/subprojects/gi-docgen/gidocgen/templates/basic/solarized-light.css @@@ -1,0 -1,0 +1,88 @@@ ++/* ++ * SPDX-FileCopyrightText: 2014 John Louis Del Rosario, Hank Gay, John Mastro, Brandon Bennett ++ * SPDX-License-Identifier: MIT ++ */ ++ ++pre { line-height: 125%; } ++td.linenos pre { color: #93a1a1; background-color: #eee8d5; padding-left: 5px; padding-right: 5px; } ++span.linenos { color: #93a1a1; background-color: #eee8d5; padding-left: 5px; padding-right: 5px; } ++td.linenos pre.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } ++span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } ++.codehilite .hll { background-color: #eee8d5 } ++.codehilite { background: #fdf6e3; color: #657b83 } ++.codehilite .c { color: #93a1a1; font-style: italic } /* Comment */ ++.codehilite .err { color: #657b83; background-color: #dc322f } /* Error */ ++.codehilite .esc { color: #657b83 } /* Escape */ ++.codehilite .g { color: #657b83 } /* Generic */ ++.codehilite .k { color: #859900 } /* Keyword */ ++.codehilite .l { color: #657b83 } /* Literal */ ++.codehilite .n { color: #657b83 } /* Name */ ++.codehilite .o { color: #93a1a1 } /* Operator */ ++.codehilite .x { color: #657b83 } /* Other */ ++.codehilite .p { color: #657b83 } /* Punctuation */ ++.codehilite .ch { color: #93a1a1; font-style: italic } /* Comment.Hashbang */ ++.codehilite .cm { color: #93a1a1; font-style: italic } /* Comment.Multiline */ ++.codehilite .cp { color: #d33682 } /* Comment.Preproc */ ++.codehilite .cpf { color: #93a1a1 } /* Comment.PreprocFile */ ++.codehilite .c1 { color: #93a1a1; font-style: italic } /* Comment.Single */ ++.codehilite .cs { color: #93a1a1; font-style: italic } /* Comment.Special */ ++.codehilite .gd { color: #dc322f } /* Generic.Deleted */ ++.codehilite .ge { color: #657b83; font-style: italic } /* Generic.Emph */ ++.codehilite .gr { color: #dc322f } /* Generic.Error */ ++.codehilite .gh { color: #657b83; font-weight: bold } /* Generic.Heading */ ++.codehilite .gi { color: #859900 } /* Generic.Inserted */ ++.codehilite .go { color: #657b83 } /* Generic.Output */ ++.codehilite .gp { color: #657b83 } /* Generic.Prompt */ ++.codehilite .gs { color: #657b83; font-weight: bold } /* Generic.Strong */ ++.codehilite .gu { color: #657b83; text-decoration: underline } /* Generic.Subheading */ ++.codehilite .gt { color: #268bd2 } /* Generic.Traceback */ ++.codehilite .kc { color: #2aa198 } /* Keyword.Constant */ ++.codehilite .kd { color: #2aa198 } /* Keyword.Declaration */ ++.codehilite .kn { color: #cb4b16 } /* Keyword.Namespace */ ++.codehilite .kp { color: #859900 } /* Keyword.Pseudo */ ++.codehilite .kr { color: #859900 } /* Keyword.Reserved */ ++.codehilite .kt { color: #b58900 } /* Keyword.Type */ ++.codehilite .ld { color: #657b83 } /* Literal.Date */ ++.codehilite .m { color: #2aa198 } /* Literal.Number */ ++.codehilite .s { color: #2aa198 } /* Literal.String */ ++.codehilite .na { color: #657b83 } /* Name.Attribute */ ++.codehilite .nb { color: #268bd2 } /* Name.Builtin */ ++.codehilite .nc { color: #268bd2 } /* Name.Class */ ++.codehilite .no { color: #268bd2 } /* Name.Constant */ ++.codehilite .nd { color: #268bd2 } /* Name.Decorator */ ++.codehilite .ni { color: #268bd2 } /* Name.Entity */ ++.codehilite .ne { color: #268bd2 } /* Name.Exception */ ++.codehilite .nf { color: #268bd2 } /* Name.Function */ ++.codehilite .nl { color: #268bd2 } /* Name.Label */ ++.codehilite .nn { color: #268bd2 } /* Name.Namespace */ ++.codehilite .nx { color: #657b83 } /* Name.Other */ ++.codehilite .py { color: #657b83 } /* Name.Property */ ++.codehilite .nt { color: #268bd2 } /* Name.Tag */ ++.codehilite .nv { color: #268bd2 } /* Name.Variable */ ++.codehilite .ow { color: #859900 } /* Operator.Word */ ++.codehilite .w { color: #657b83 } /* Text.Whitespace */ ++.codehilite .mb { color: #2aa198 } /* Literal.Number.Bin */ ++.codehilite .mf { color: #2aa198 } /* Literal.Number.Float */ ++.codehilite .mh { color: #2aa198 } /* Literal.Number.Hex */ ++.codehilite .mi { color: #2aa198 } /* Literal.Number.Integer */ ++.codehilite .mo { color: #2aa198 } /* Literal.Number.Oct */ ++.codehilite .sa { color: #2aa198 } /* Literal.String.Affix */ ++.codehilite .sb { color: #2aa198 } /* Literal.String.Backtick */ ++.codehilite .sc { color: #2aa198 } /* Literal.String.Char */ ++.codehilite .dl { color: #2aa198 } /* Literal.String.Delimiter */ ++.codehilite .sd { color: #93a1a1 } /* Literal.String.Doc */ ++.codehilite .s2 { color: #2aa198 } /* Literal.String.Double */ ++.codehilite .se { color: #2aa198 } /* Literal.String.Escape */ ++.codehilite .sh { color: #2aa198 } /* Literal.String.Heredoc */ ++.codehilite .si { color: #2aa198 } /* Literal.String.Interpol */ ++.codehilite .sx { color: #2aa198 } /* Literal.String.Other */ ++.codehilite .sr { color: #cb4b16 } /* Literal.String.Regex */ ++.codehilite .s1 { color: #2aa198 } /* Literal.String.Single */ ++.codehilite .ss { color: #2aa198 } /* Literal.String.Symbol */ ++.codehilite .bp { color: #268bd2 } /* Name.Builtin.Pseudo */ ++.codehilite .fm { color: #268bd2 } /* Name.Function.Magic */ ++.codehilite .vc { color: #268bd2 } /* Name.Variable.Class */ ++.codehilite .vg { color: #268bd2 } /* Name.Variable.Global */ ++.codehilite .vi { color: #268bd2 } /* Name.Variable.Instance */ ++.codehilite .vm { color: #268bd2 } /* Name.Variable.Magic */ ++.codehilite .il { color: #2aa198 } /* Literal.Number.Integer.Long */ diff --cc subprojects/gi-docgen/gidocgen/templates/basic/struct.html index 5fd9b7593b,0000000000..0b0f27a202 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/struct.html +++ b/subprojects/gi-docgen/gidocgen/templates/basic/struct.html @@@ -1,216 -1,0 +1,236 @@@ + + +{% extends "base.html" %} + +{% block title %}{{ namespace.name }}.{{ struct.name }}{% endblock %} + +{% block meta_other %} + + + + +{% endblock %} + +{% macro sidebar_block(elements, struct_name, section_title, section_class, section_fragment) -%} +{% if elements|length > 0 %} +
    +
    {{ section_title }}
    + +
    +{% endif %} +{% endmacro %} + +{% block sidebar %} +
    +
    Type
    + +
    + +{{ sidebar_block(struct.ctors, struct.name, "Constructors", "ctor", "ctor") }} - {{ sidebar_block(struct.methods, struct.name, "Instance methods", "method", "method") }} +{{ sidebar_block(struct.type_funcs, struct.name, "Functions", "func", "type_func") }} ++{{ sidebar_block(struct.methods, struct.name, "Instance methods", "method", "method") }} ++{% endblock %} ++ ++{% macro navbar_block(elements, section_title, section_link) -%} ++{% if elements|length > 0 %} ++
  • {{ section_title }}
  • ++{% endif %} ++{% endmacro %} ++ ++{% block navbar %} ++
    ++ ++
    +{% endblock %} + +{% block content %} +
    +
    +

    Struct

    +

    {{ namespace.name }}{{ struct.name }}

    +
    + +
    + +
    +

    + Description + + {% if CONFIG.source_location_url and struct.docs_location %} + [src] + {% endif %} +

    + +
    {{ struct.c_decl }}
    + +
    + {{ struct.description }} +
    + + {% if struct.fields %} +
    +
    + Structure members + {% if CONFIG.source_location_url and struct.source_location %} + [src] + {% endif %} +
    + +
    + + {% for field in struct.fields %} + + + + + {% endfor %} +
    {{ field.name }}{{ field.description }}
    +
    +
    + {% endif %} + +
    + + {% if struct.stability %} + + {% endif %} + {% if struct.available_since %} + + {% endif %} + {% if struct.deprecated_since %} + + + {% endif %} +
    Stability:{{ struct.stability }}
    Available since:{{ struct.available_since }}
    Deprecated since:{{ struct.deprecated_since.version }}
    {{ struct.deprecated_since.message }}
    +
    + + {% if struct.attributes %} +
    + + {% for (key, value) in struct.attributes.items() %} + + {% endfor %} +
    {{ key|escape }}{{ value|escape }}
    +
    + {% endif %} +
    +
    + + {% if struct.ctors %} +
    +

    + Constructors + +

    + +
    + {% for ctor in struct.ctors %} +
    +
    {{ ctor.identifier }}
    + +
    + {{ ctor.summary }} +
    + + {% if ctor.available_since or ctor.deprecated_since -%} +
    + {%- if ctor.available_since -%} +

    Available since: {{ ctor.available_since }}

    + {%- endif -%} + {%- if ctor.deprecated_since -%} +

    Deprecated since: {{ ctor.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} +
    + {% endfor %} +
    +
    + {% endif %} + ++ {% if struct.type_funcs %} ++
    ++

    ++ Functions ++ ++

    ++ ++
    ++ {% for func in struct.type_funcs %} ++
    ++
    {{ func.identifier }}
    ++ ++
    ++ {{ func.summary }} ++
    ++ ++ {% if func.available_since or func.deprecated_since -%} ++
    ++ {%- if func.available_since -%} ++

    Available since: {{ func.available_since }}

    ++ {%- endif -%} ++ {%- if func.deprecated_since -%} ++

    Deprecated since: {{ func.deprecated_since }}

    ++ {%- endif -%} ++
    ++ {%- endif %} ++
    ++ {% endfor %} ++
    ++
    ++ {% endif %} ++ + {% if struct.methods %} +
    +

    + Instance methods + +

    + +
    + {% for method in struct.methods %} +
    +
    {{ method.identifier }}
    + +
    + {{ method.summary }} +
    + + {% if method.available_since or method.deprecated_since -%} +
    + {%- if method.available_since -%} +

    Available since: {{ method.available_since }}

    + {%- endif -%} + {%- if method.deprecated_since -%} +

    Deprecated since: {{ method.deprecated_since }}

    + {%- endif -%} +
    + {%- endif %} +
    + {% endfor %} +
    + +
    + {% endif %} + - {% if struct.type_funcs %} -
    -

    - Functions - -

    - -
    - {% for func in struct.type_funcs %} -
    -
    {{ func.identifier }}
    - -
    - {{ func.summary }} -
    - - {% if func.available_since or func.deprecated_since -%} -
    - {%- if func.available_since -%} -

    Available since: {{ func.available_since }}

    - {%- endif -%} - {%- if func.deprecated_since -%} -

    Deprecated since: {{ func.deprecated_since }}

    - {%- endif -%} -
    - {%- endif %} -
    - {% endfor %} -
    -
    - {% endif %} - +
    +
    +{% endblock %} diff --cc subprojects/gi-docgen/gidocgen/templates/basic/style.css index 8ff4bf13af,0000000000..889bbe8bc7 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/style.css +++ b/subprojects/gi-docgen/gidocgen/templates/basic/style.css @@@ -1,869 -1,0 +1,901 @@@ +/* + * SPDX-FileCopyrightText: 2021 GNOME Foundation + * + * SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + */ + - @import url("pygment.css"); ++@import url("solarized-light.css") (prefers-color-scheme: light); ++@import url("solarized-dark.css") (prefers-color-scheme: dark); ++ +@import url("fonts.css"); + +/********************************* + * LIGHT THEME + *********************************/ +:root { + + /* colors */ + --text-color: #333; + --text-color-muted: #999; + --primary: rgb(28, 118, 228); + --body-bg: #fff; + --sidebar-primary: rgb(144, 194, 255); + --sidebar-bg: #151515; + --sidebar-selected-bg: var(--primary); + --sidebar-hover-bg: rgba(127, 127, 127, 0.2); + --sidebar-text-color: #fafafa; + --sidebar-padding: 1.5em; + + /* boxes, e.g. code blocks */ + --box-bg: rgba(135, 135, 135, 0.085); + --box-radius: 0.35rem; + --box-padding: 0.75rem; + --box-margin: 0.75rem 0; + --box-text-color: #111; + + /* typography */ + --body-font-family: "Red Hat Text",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + --body-font-scale: 0.95; - --body-font-size: calc(var(--body-font-scale) * clamp(16px, 1vw, 20px)); ++ --body-font-size: calc(var(--body-font-scale) * clamp(16px, 1vw, 18px)); + --body-font-weight: normal; + + --monospace-font-family: "Source Code Pro", monospace; + --monospace-font-size: calc(0.86 * var(--body-font-size)); /* Monospace fonts are very different in terms of font-sizes. Adjust this value to scale it */ + + --heading-font-family: "Red Hat Display", var(--body-font-family); + --heading-weight: 900; + --heading-font-scale: 1.05; + + --heading-small-font-family: var(--heading-font-family); + --heading-small-weight: 600; + --heading-small-font-scale: 1; + + --heading-table-font-family: var(--heading-font-family); + --heading-table-weight: 600; + + --heading-docblock-color: #6d6d6d; /* docblocks have headings from source comments. we want them to differ.*/ + --heading-docblock-scale: 0.9; /* docblocks have headings from source comments. we want them to differ.*/ + + --symbol-font-family: var(--heading-font-family); + --symbol-font-weight: 500; + --symbol-font-scale: 1; + + --table-font-size: 0.92em; /* Tables often contain lots information. It's better to scale them down a big to get more sutff fitted inside */ + + /* misc */ + --prefered-content-width: 90ch; /* The preferred width for the readable content */ + --anchor-sign: "#"; + +} + +/********************************* + * DARK THEME (overrides) + *********************************/ + @media (prefers-color-scheme: dark) { + :root { + --primary: rgb(144, 194, 255); + --text-color: #f6f6f6; + --text-color-muted: #686868; + --body-bg: #121212; + --sidebar-primary: rgb(144, 194, 255); + --sidebar-bg: #1e1e1e; + --sidebar-selected-bg: rgb(17, 112, 228); + --sidebar-text-color: #fafafa; + --box-bg: rgba(135, 135, 135, 0.1); + --box-text-color: #fff; + --heading-docblock-color: #b7b7b7; + } - - /* fix dark theme syntax highlighting with a filter (for now) */ - .highlight pre span { - filter: brightness(6); - } +} + +/********************************* + * GENERAL STYLING + *********************************/ +*, +*:before, +*:after { + box-sizing: border-box; +} + +::-moz-selection { + color: white; + background: var(--primary); +} + +::selection { + color: white; + background: var(--primary); +} + +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-thumb { + border-radius: 10px; + background: rgba(128, 128, 128, 0.6); +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(128, 128, 128, 1); +} + +::-webkit-scrollbar-track { + background: rgba(128, 128, 128, 0.15); +} + +* { + scrollbar-width: initial; +} + +body { + font: 16px/1.5 var(--body-font-family); + font-weight: var(--body-font-weight); + font-size: var(--body-font-size); + margin: 0; + padding: 0; + position: relative; + + -webkit-font-feature-settings: "kern", "liga"; + -moz-font-feature-settings: "kern", "liga"; + font-feature-settings: "kern", "liga"; + color: var(--text-color); + background: var(--body-bg); +} + +h1, h2, h3, h4, h5, h6 { + font-family: var(--heading-font-family); + font-weight: var(--heading-weight); + margin: 1.75em 0 0.75em 0; + display: flex; + align-items: center; +} + +h1 { + font-size: calc(1.75em * var(--heading-font-scale)); +} + + +header h1 { + margin-top: 0; +} + +h2 { + font-size: calc(1.4em * var(--heading-font-scale)); +} + +h3 { + font-size: calc(1.2em * var(--heading-font-scale)); +} + +header h3 { + color: var(--text-color-muted); + margin-bottom: 0; +} + +h4, h5 { + font-size: calc(1em * var(--heading-font-scale)); +} + +h6 { + font-size: calc(1em * var(--heading-small-font-scale)); + font-family: var(--heading-small-font-family); + font-weight: var(--heading-small-weight); +} + +ol, ul { + padding-left: 1rem; +} + +ul ul, ol ul, ul ol, ol ol { + margin-bottom: .6em; +} + +p { + margin: 0 0 .6em 0; +} + +a { + color: var(--primary); + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +summary { + outline: none; +} + +blockquote { + border-left: 3px solid var(--primary); + background: var(--box-bg); + padding: var(--box-padding); + border-radius: var(--box-radius); + margin: var(--box--margin); +} + +span.sep::after { + content: "▸"; +} + +span.sep { + font-size: calc(0.5em * var(--monospace-font-size)); + opacity: 0.55; + padding-left: .25em; + padding-right: .25em; +} + +code, +pre { + font-family: var(--monospace-font-family); + font-size: var(--monospace-font-size); + color: var(--box-text-color); +} + +pre { + background: var(--box-bg); + padding: var(--box-padding); + border-radius: var(--box-radius); + overflow: auto; +} + +code { + background: var(--box-bg); + padding: 0 0.35em; + border-radius: 0.35rem; + word-break: break-word; +} + +a > code { + color: var(--primary); +} + + +pre pre, +pre code { + padding: 0; + margin: 0; + font-size: 1em; + background: none; + color: inherit; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + font-family: inherit; + font-weight: inherit; + font-size: 0.85em; +} + +strong, b { + font-weight: 600; +} + +/* fix alignment of images on small screen */ +img, svg { + display: block; + max-width: 100%; + height: auto; +} + +svg .node polygon, svg .node path { + transition: fill 150ms ease; + fill: var(--box-bg); + stroke: none; +} + +svg .node a { + text-decoration: none !important; +} + +svg .node a text { + fill: var(--text-color); + font-family: var(--body-font-family); +} + +svg .node.link text { + fill: var(--primary); +} + +svg .node.link:hover polygon, svg .node.link:hover path { + fill: var(--sidebar-hover-bg); +} +svg .node.link:hover text { + fill: var(--box-text-color); +} +svg .edge path { + stroke: var(--text-color); +} + +/* fix unwanted margins in tables, code, lists and blockquotes */ +li > *:first-child, +li > *:first-child > *:first-child, +li > *:first-child > *:first-child > *:first-child, +td > *:first-child, +td > *:first-child > *:first-child, +td > *:first-child > *:first-child > *:first-child, +pre > *:first-child, +pre > *:first-child > *:first-child, +pre > *:first-child > *:first-child > *:first-child, +blockquote > *:first-child, +blockquote > *:first-child > *:first-child, +blockquote > *:first-child > *:first-child > *:first-child { + margin-top: 0; +} +li > *:last-child, +li > *:last-child > *:last-child, +li > *:last-child > *:last-child > *:last-child, +td > *:last-child, +td > *:last-child > *:last-child, +td > *:last-child > *:last-child > *:last-child, +pre > *:last-child, +pre > *:last-child > *:last-child, +pre > *:last-child > *:last-child > *:last-child, +blockquote > *:last-child, +blockquote > *:last-child > *:last-child, +blockquote > *:last-child > *:last-child > *:last-child { + margin-bottom: 0; +} + +/********************************* + * PAGE STRUCTURE + *********************************/ +#body-wrapper { + display: flex; + flex-wrap: nowrap; + flex-direction: row; +} + +#body-wrapper:focus { + outline: none; +} + +#main { + position: relative; + flex-grow: 1; + min-width: 0; + box-shadow: 0 0 134px rgba(0, 0, 0, 0.1); +} + +footer { + width: 100%; + display: none; +} + +/********************************* + * Button + *********************************/ + +#btn-to-top { + position: fixed; + bottom: 12px; + right: 32px; + z-index: 1000; + border-radius: 50%; + width: 42px; + height: 42px; + border: 1px solid var(--primary); + background: var(--box-bg); + color: var(--text-color); + cursor: pointer; + text-transform: none; +} + +#btn-to-top > .up-arrow { + margin-left: -2px; +} + +#btn-to-top > .up-arrow:after { + content: url(go-up-symbolic.png); +} + +/********************************* + * SIDEBAR + *********************************/ +.sidebar { + scrollbar-width: thin; + background: var(--sidebar-bg); + border-right: 1px solid var(--sidebar-bg); + min-width: 35ch; + padding: var(--sidebar-padding); + color: var(--sidebar-text-color); + position: sticky; + top: 0; + z-index: 2; + height: 100vh; + overflow-y: auto; +} + +.sidebar a, +.sidebar a:hover { + text-decoration: none; +} + +.sidebar .logo { + display: block; + margin: 1rem auto 1.2rem auto; + width: 50%; +} + +.sidebar .section > ul > li { + margin-right: -10px; +} + +.sidebar .section h3, .sidebar .section h5 { + text-align: left; + padding-left: 0.5rem; + padding-right: 0.5rem; + font-weight: var(--heading-weight); +} + +.sidebar .section h5 { + font-size: 1em; + margin-bottom: 0.5em; +} + +.sidebar .namespace > h3 { + margin-bottom: 0; + padding: 0; + font-size: 1.5em; + text-transform: uppercase; + font-weight: 900; +} + +.sidebar .namespace > p { + font-size: 0.9em; + opacity: 0.8; + padding-left: 0.5rem; +} + +.sidebar .section { + padding-left: 0.5rem; + padding-right: 0.5rem; + font-size: 80%; +} + +.sidebar .links { + margin-bottom: 1rem; +} + +.sidebar .section a { + display: block; + text-overflow: ellipsis; + overflow: hidden; + transition: background-color 150ms ease; + color: var(--sidebar-primary); + border-radius: var(--box-radius); + padding: 0.2rem 0.5rem; + margin-bottom: 0.15rem; +} + +.sidebar .section a:hover { + background-color: var(--sidebar-hover-bg); + color: var(--sidebar-text-color); +} + +.sidebar .section a.current { + background-color: var(--sidebar-selected-bg); + color: white; +} + +.sidebar .search { + box-sizing: border-box; + text-align: center; +} + +.sidebar .search input[type="text"] { + border-color: transparent; + width: 100%; + border: 1px solid #ccc; + border-radius: 50px; + padding: 6px 12px; + display: inline-block; + font-size: 14px; + box-shadow: inset 0 1px 3px #ddd; + transition: border .3s linear; +} + ++.toc { ++ display: block; ++ margin-top: 2em; ++ z-index: 3; ++ min-width: 15ch; ++ font-size: 80%; ++} ++ ++.toc nav { ++ margin-left: 2em; ++ margin-right: 2em; ++} ++ ++#toc-title { ++ text-transform: uppercase; ++ font-weight: var(--heading-weight); ++} ++ ++.toc-list { ++ list-style-type: none; ++ margin: 0; ++ padding-left: 0; ++} ++ ++.toc-list-item { ++ padding-top: .25em; ++} ++ +/********************************* + * ANCHORS & TOGGLERS + *********************************/ +.anchor, +.md-anchor { + position: relative; + z-index: 1; + text-decoration: none; + padding: 0 0.5em; + color: var(--text-color-muted); +} + +.anchor:hover, +.md-anchor:hover { + color: var(--primary); +} + +.anchor:not([href]), +.md-anchor:not([href]) { + display: none; +} + +.anchor:before, +.md-anchor:before { + content: var(--anchor-sign); /*'§'*/ +} + +.toggle-wrapper { + position: relative; +} + +.collapse-toggle { + position: absolute; + right: 0; + left: -2em; + white-space: nowrap; + text-decoration: none; + font-size: 0.8em; + color: transparent; +} + +.collapse-toggle > .inner { + width: 1rem; + height: 1rem; + border-radius: calc(0.75 * var(--box-radius)); + display: inline-flex; + justify-content: center; + align-items: center; + text-align: center; + vertical-align: middle; + color: var(--box-text-color); + position: relative; + left: -0.25rem; + font-family: monospace; + font-size: 0.7rem; + font-weight: bold; + background: var(--box-bg); +} + +/********************************* + * UTILITY + *********************************/ +.deprecated > h6 > a { + opacity: 0.65; +} + +.hidden { + display: none !important; +} + +/********************************* + * CONTENT STYLING + *********************************/ +.content { + padding: 2em 4em; + overflow: visible; + max-width: calc(var(--prefered-content-width) + 8em); +} + +.content table:not(.table-display) { + border-spacing: 0 0.25rem; +} + +.content td { + vertical-align: top; +} + +.content td:first-child { + padding-right: 1rem; +} + +.content td p:first-child { + margin-top: 0; +} + +.content td h1, .content td h2 { + margin-left: 0; + font-size: 1.1em; +} + +.content tr:first-child td { + border-top: 0; +} + +kbd { + display: inline-block; + padding: 3px 5px; + font: 15px monospace; + line-height: 10px; + vertical-align: middle; + border: solid 1px; + border-radius: 3px; + box-shadow: inset 0 -1px 0; + cursor: default; +} + +.content tr:first-child { + border-bottom: 1px solid rgba(0, 0, 0, 0.35); +} + +.content td { + vertical-align: top; +} + +.content td:first-child { + padding-right: 1rem; +} + +.content td p:first-child { + margin-top: 0; +} + +.content td h4, .content td h5 { + margin-left: 0; + font-size: 1.1em; +} + +.content tr:first-child td { + border-top: 0; +} + +.srclink { + color: var(--text-color-muted); + font-size: 1rem; + font-weight: var(--body-font-weight); + flex-grow: 0; + text-decoration: none; + margin-left: auto; + position: relative; + z-index: 1; +} + +.meta tr > td:not(:first-child) { + width: 100%; +} + +.meta tr > td:first-child { + white-space: nowrap; +} + +/********************************* + * DOCBLOCK STYLING + *********************************/ +.docblock { + position: relative; + text-align: left; +} + +.docblock h1 { + font-size: calc(1.3em * var(--heading-docblock-scale) * var(--heading-font-scale)); +} + +.docblock h2 { + font-size: calc(1.2em * var(--heading-docblock-scale) * var(--heading-font-scale)); +} + +.docblock h3 { + font-size: calc(1.1em * var(--heading-docblock-scale) * var(--heading-font-scale)); +} + +.docblock h4 { + font-size: calc(1.05em * var(--heading-docblock-scale) * var(--heading-font-scale)); +} + +.docblock h1, +.docblock h2, +.docblock h3, +.docblock h4, +.docblock h5, +.docblock h6 { + color: var(--heading-docblock-color) +} + +.docblock table { + margin: .25em 0; + max-width: 100%; + font-size: var(--table-font-size); +} + +.docblock table td { + padding: .25em; +} + +.docblock table th { + padding: .25em; + text-align: left; + font-family: var(--heading-table-font-family); + font-weight: var(--heading-table-weight); +} + +.docblock table tr th:first-child, +.docblock table tr td:first-child { + padding-left: 0; +} + +.docblock table tr th:last-child, +.docblock table tr td:last-child { + padding-right: 0; +} + +table.enum-members, +table.results { + border-radius: var(--box-radius); + border: 1px solid var(--text-color-muted); + border-spacing: 0 0 !important; + font-size: 80%; +} + +table.enum-members tr th, +table.results tr th { + border-top-color: var(--body-bg); + background-color: var(--box-bg); + border-bottom: 1px solid var(--text-color-muted); +} + +table.enum-members tr th:first-child, +table.enum-members tr td:first-child { + min-width: 25em; + padding-left: .5em; +} + +table.results tr th:first-child, +table.results tr td:first-child { + padding-left: .5em; +} + +table.enum-members tr th:last-child, +table.enum-members tr td:last-child, +table.results tr th:last-child, +table.results tr td:last-child { + max-width: 35em; + padding-right: .5em; +} + +table.results tr td code { + font-size: 100%; +} + +table.arguments tr td, +table.returns tr td { + color: var(--text-color-muted); +} + +table.arguments tr td:first-child, +table.returns tr td:first-child { + min-width: 12em; +} + +table.arguments tr.arg-name td, +table.arguments tr.arg-description td, +table.returns tr.arg-name td, +table.returns tr.arg-description td { + color: var(--text-color); +} + +.docblock ul li, +.docblock ol li { + padding-top: 0.15rem; + padding-bottom: 0.15rem; +} + +.docblock ul.type { + list-style: none; +} + +.docblock ul.type li::before { + content: "»"; + color: var(--text-color); + display: inline-block; + width: 1em; + margin-left: -1em; +} + +.docblock .codehilite { + position: relative; +} +.docblock .codehilite > .copy-button { + position: absolute; + top: 0; + right: 0; + + border: none; + background: none; + + margin: var(--box-padding); + cursor: pointer; +} + +.docblock .codehilite > .copy-button { + transition: background-color 150ms ease; + color: var(--primary); + border-radius: var(--box-radius); + padding: 0.2rem 0.5rem; + margin: var(--box-padding); +} + +.docblock .codehilite > .copy-button:hover { + background-color: var(--sidebar-hover-bg); + color: var(--text-color); +} + +.docblock .codehilite > .copy-button:active { + background-color: var(--primary); +} + + +/************************************************************* + SYMBOLS +**************************************************************/ +.symbol, +.constructors h6, +.methods h6, +.signals h6, +.properties h6, +.type-funcs h6, +.implements a, +.ancestors a, ++.descendants a, ++.implementations a, +.sidebar .links a ++.toc a +{ + font-family: var(--symbol-font-family); + font-size: calc(1em * var(--symbol-font-scale)); + font-weight: var(--symbol-font-weight); +} + +/************************** + RESPONSIVENESS +**************************/ +@media (max-width: 700px) { + body { + padding-top: 0px; + } + + #body-wrapper { + flex-direction: column; + overflow: hidden; + } + + #main { + width: 100%; + padding: 2rem; + } + + .sidebar { + position: static; + height: initial; + order: 1; + } ++ ++ .toc { ++ display: hidden; ++ } +} diff --cc subprojects/gi-docgen/gidocgen/templates/basic/type_func.html index babde7a85c,0000000000..aadadfb958 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/type_func.html +++ b/subprojects/gi-docgen/gidocgen/templates/basic/type_func.html @@@ -1,184 -1,0 +1,185 @@@ + + +{% extends "base.html" %} + +{% block title %}{{ namespace.name }}.{{ class.name }}.{{ type_func.name }}{% endblock %} + +{% block meta_other %} + + + + +{% endblock %} + +{% block sidebar %} +
    +
    Type
    + +
    +
    +
    Functions
    + +
    +{% endblock %} + +{% block content %} +
    +
    +

    Function

    +

    {{ namespace.name }}{{ class.name }}{{ type_func.name }}

    +
    + +
    +
    +

    + Declaration + + {% if CONFIG.source_location_url and type_func.source_location %} + [src] + {% endif %} +

    + +
    +
    {{ type_func.c_decl }}
    +
    +
    + +
    +

    + Description + + {% if CONFIG.source_location_url and type_func.docs_location %} + [src] + {% endif %} +

    + +
    + {{ type_func.description }} +
    + +
    + + {% if type_func.stability %} + + {% endif %} + {% if type_func.available_since %} + + {% endif %} + {% if type_func.deprecated_since %} + + + {% endif %} +
    Stability:{{ type_func.stability }}
    Available since:{{ type_func.available_since }}
    Deprecated since:{{ type_func.deprecated_since.version }}
    {{ type_func.deprecated_since.message }}
    +
    + + {% if type_func.attributes %} +
    + + {% for (key, value) in type_func.attributes.items() %} + + {% endfor %} +
    {{ key|escape }}{{ value|escape }}
    +
    + {% endif %} +
    + + {% if type_func.arguments|length != 0 %} +
    +

    + Parameters + +

    + +
    + + {% for arg in type_func.arguments %} + + + + + + + + + {% if arg.direction != "in" %}{% endif %} + {% if arg.direction == "in" and arg.is_pointer and arg.nullable %}{% endif %} + {% if arg.direction == "out" and arg.is_pointer and arg.nullable %}{% endif %} + {% if arg.optional %}{% endif %} + {% if arg.is_array and arg.zero_terminated %}{% endif %} + {% if arg.is_array and arg.fixed_size > 0 %}{% endif %} + {% if arg.is_array and arg.len_arg %}{% endif %} + {% if arg.is_pointer %}{% endif %} + {% if arg.string_note %}{% endif %} + {% endfor %} + {% if type_func.throws %} + + + + + + + + + {% endif %} +
    {{ arg.name }} + {%- if arg.is_array -%}An array of {%- endif -%} + {%- if arg.is_list -%}A list of {%- endif -%} + {%- if arg.link -%} + {{ arg.link|safe }} + {%- else -%} + {{ arg.type_cname }} + {%- endif -%} +
     {{ arg.description|safe }}
     {{ arg.direction_note }}
     The argument can be NULL.
     The argument can be set to NULL.
     The argument can be NULL.
     The array must be NULL-terminated.
     The array must have {{ arg.fixed_size }} elements.
     The length of the array is specified in the {{ arg.len_arg }} argument.
     {{ arg.transfer_note }}
     {{ arg.string_note }}
    errorGError **
     The return location for a GError*, or NULL.
    +
    +
    + {% endif %} + + {% if type_func.return_value %} +
    +

    + Return value + +

    + +
    + + + + + + + + + + {% if type_func.return_value.is_array and type_func.return_value.zero_terminated %}{% endif %} + {% if type_func.return_value.is_array and type_func.return_value.fixed_size > 0 %}{% endif %} + {% if type_func.return_value.is_array and type_func.return_value.len_arg %}{% endif %} + {% if type_func.return_value.is_pointer %}{% endif %} + {% if type_func.return_value.is_pointer and type_func.return_value.nullable %}{% endif %} + {% if type_func.return_value.string_note %}{% endif %} +
    Returns: + {%- if type_func.return_value.is_array -%}An array of {%- endif -%} + {%- if type_func.return_value.is_list -%}A list of {%- endif -%} ++ {%- if type_func.return_value.is_list_model -%}A list model of {%- endif -%} + {%- if type_func.return_value.link -%} + {{ type_func.return_value.link|safe }} + {%- else -%} + {{ type_func.return_value.type_cname }} + {%- endif -%} +
     {{ type_func.return_value.description|safe }}
     The array is NULL-terminated.
     The array has {{ type_func.return_value.fixed_size }} elements.
     The length of the array is in the {{ type_func.return_value.len_arg }} argument.
     {{ type_func.return_value.transfer_note }}
     The return value can be NULL.
     {{ type_func.return_value.string_note }}
    +
    +
    + {% endif %} +
    +
    +{% endblock %} diff --cc subprojects/gi-docgen/gidocgen/templates/basic/vfunc.html index ef48af93ee,0000000000..b62c08a8c8 mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/templates/basic/vfunc.html +++ b/subprojects/gi-docgen/gidocgen/templates/basic/vfunc.html @@@ -1,185 -1,0 +1,186 @@@ + + +{% extends "base.html" %} + +{% block title %}{{ namespace.name }}.{{ class.name }}.{{ vfunc.name }}{% endblock %} + +{% block meta_other %} + + + + +{% endblock %} + +{% block sidebar %} +
    +
    Type
    + +
    +
    +
    Virtual methods
    + +
    +{% endblock %} + +{% block content %} +
    +
    +

    Virtual Method

    +

    {{ namespace.name }}{{ class.name }}{{ vfunc.name }}

    +
    + +
    +
    +

    + Declaration + + {% if CONFIG.source_location_url and vfunc.source_location %} + [src] + {% endif %} +

    + +
    +
    {{ vfunc.c_decl }}
    +
    +
    + +
    +

    + Description + + {% if CONFIG.source_location_url and vfunc.docs_location %} + [src] + {% endif %} +

    + +
    + {{ vfunc.description }} +
    + +
    + + {% if vfunc.stability %} + + {% endif %} + {% if vfunc.available_since %} + + {% endif %} + {% if vfunc.deprecated_since %} + + + {% endif %} +
    Stability:{{ vfunc.stability }}
    Available since:{{ vfunc.available_since }}
    Deprecated since:{{ vfunc.deprecated_since.version }}
    {{ vfunc.deprecated_since.message }}
    +
    + + {% if vfunc.attributes %} +
    + + {% for (key, value) in vfunc.attributes.items() %} + + {% endfor %} +
    {{ key|escape }}{{ value|escape }}
    +
    + {% endif %} +
    + + {% if vfunc.arguments|length != 0 %} +
    +

    + Parameters + +

    + +
    + + {% for arg in vfunc.arguments %} + + + + + + + + + {% if arg.direction != "in" %}{% endif %} + {% if arg.direction == "in" and arg.is_pointer and arg.nullable %}{% endif %} + {% if arg.direction == "out" and arg.is_pointer and arg.nullable %}{% endif %} + {% if arg.optional %}{% endif %} + {% if arg.is_array and arg.zero_terminated %}{% endif %} + {% if arg.is_array and arg.fixed_size > 0 %}{% endif %} + {% if arg.is_array and arg.len_arg %}{% endif %} + {% if arg.is_pointer %}{% endif %} + {% if arg.string_note %}{% endif %} + {% endfor %} + {% if vfunc.throws %} + + + + + + + + + {% endif %} +
    {{ arg.name }} + {%- if arg.is_array -%}An array of {%- endif -%} + {%- if arg.is_list -%}A list of {%- endif -%} + {%- if arg.link -%} + {{ arg.link|safe }} + {%- else -%} + {{ arg.type_cname }} + {%- endif -%} +
     {{ arg.description|safe }}
     {{ arg.direction_note }}
     The argument can be NULL.
     The argument can be set to NULL.
     The argument can be NULL.
     The array must be NULL-terminated.
     The array must have {{ arg.fixed_size }} elements.
     The length of the array is specified in the {{ arg.len_arg }} argument.
     {{ arg.transfer_note }}
     {{ arg.string_note }}
    errorGError **
     The return location for a GError*, or NULL.
    +
    +
    + {% endif %} + + {% if vfunc.return_value %} +
    +

    + Return value + +

    + +
    + + + + + + + + + + {% if vfunc.return_value.is_array and vfunc.return_value.zero_terminated %}{% endif %} + {% if vfunc.return_value.is_array and vfunc.return_value.fixed_size > 0 %}{% endif %} + {% if vfunc.return_value.is_array and vfunc.return_value.len_arg %}{% endif %} + {% if vfunc.return_value.is_pointer %}{% endif %} + {% if vfunc.return_value.is_pointer and vfunc.return_value.nullable %}{% endif %} + {% if vfunc.return_value.string_note %}{% endif %} +
    Returns: + {%- if vfunc.return_value.is_array -%}An array of {%- endif -%} + {%- if vfunc.return_value.is_list -%}A list of {%- endif -%} ++ {%- if vfunc.return_value.is_list_model -%}A list model of {%- endif -%} + {%- if vfunc.return_value.link -%} + {{ vfunc.return_value.link|safe }} + {%- else -%} + {{ vfunc.return_value.type_cname }} + {%- endif -%} +
     {{ vfunc.return_value.description|safe }}
     The array is NULL-terminated.
     The array has {{ vfunc.return_value.fixed_size }} elements.
     The length of the array is in the {{ vfunc.return_value.len_arg }} argument.
     {{ vfunc.return_value.transfer_note }}
     The return value can be NULL.
     {{ vfunc.return_value.string_note }}
    +
    +
    + {% endif %} + +
    +
    +{% endblock %} diff --cc subprojects/gi-docgen/gidocgen/utils.py index c32eeccb8d,0000000000..e2ed0f3a2b mode 100644,000000..100644 --- a/subprojects/gi-docgen/gidocgen/utils.py +++ b/subprojects/gi-docgen/gidocgen/utils.py @@@ -1,870 -1,0 +1,894 @@@ +# SPDX-FileCopyrightText: 2021 GNOME Foundation +# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +import markdown +import os +import re +import subprocess +import sys + +from markupsafe import Markup +from pygments import highlight +from pygments.lexers import get_lexer_by_name +from pygments.formatters import HtmlFormatter +from typogrify.filters import typogrify + +from . import gir, log, mdext, porter + + +# The beginning of a gtk-doc code block: +# +# |[ (optional language identifier) +# +CODEBLOCK_START_RE = re.compile( + r''' + ^ + \s* + \|\[ + \s* + (?P\<\!-- \s* language="\w+" \s* --\>)? + \s* + $ + ''', + re.UNICODE | re.VERBOSE) + +# The optional language identifier for a gtk-doc code block: +# +# +# +LANGUAGE_RE = re.compile( + r''' + ^ + \s* + + \s* + $ + ''', + re.UNICODE | re.VERBOSE) + +# The ending of a gtk-doc code block: +# +# ]| +# +CODEBLOCK_END_RE = re.compile( + r''' + ^ + \s* + \]\| + \s* + $ + ''', + re.UNICODE | re.VERBOSE) + +LINK_RE = re.compile( + r''' ++ (?P\[ [\w\s,\-_:]+ \])? + \[ + (`)? + (?P[\w]+) + @ + (?P[\w\-_:\.]+) + (`)? + \] + ''', + re.VERBOSE) + +TYPE_RE = re.compile( + r''' + (?P[\w]+\.)? # namespace (optional) + (?P[\w]+) # type name + ''', + re.VERBOSE) + +PROPERTY_RE = re.compile( + r''' + (?P[\w]+\.)? # namespace (optional) + (?P[\w]+) # type name + :{1} # delimiter + (?P[\w-]*\w) # property name + ''', + re.VERBOSE) + +SIGNAL_RE = re.compile( + r''' + (?P[\w]+\.)? # namespace (optional) + (?P[\w]+) # type name + :{2} # delimiter + (?P[\w-]*\w) # signal name + ''', + re.VERBOSE) + +METHOD_RE = re.compile( + r''' + (?P[\w]+\.)? # namespace (optional) + (?P[\w]+) # type name + \. # delimiter + (?P[\w_]*\w) # method name + ''', + re.VERBOSE) + +CAMEL_CASE_START_RE = re.compile(r"([A-Z]+)([A-Z][a-z])") + +CAMEL_CASE_CHUNK_RE = re.compile(r"([a-z\d])([A-Z])") + +LANGUAGE_MAP = { + 'c': 'c', + 'css': 'css', + 'plain': 'plain', + 'xml': 'xml', ++ 'javascript': 'javascript', +} + +MD_EXTENSIONS = [ + # Standard extensions + 'codehilite', + 'def_list', + 'fenced_code', + 'meta', + 'tables', + 'toc', + + # Local extensions + mdext.GtkDocExtension(), +] + +MD_EXTENSIONS_CONF = { + 'codehilite': {'guess_lang': False}, + 'toc': {'permalink_class': 'md-anchor', 'permalink': ''}, +} + +EN_STOPWORDS = set(""" +a and are as at +be but by +for +if in into is it +near no not +of on or +such +that the their then there these they this to +was will with +""".split()) + + +def process_language(lang): + if lang is None: + return "plain" + + res = LANGUAGE_RE.match(lang) + if res: + language = res.group("language") or "plain" + else: + language = "plain" + + return LANGUAGE_MAP[language.lower()] + + +class LinkParseError: + def __init__(self, line=None, start=0, end=0, fragment=None, rest=None, message="Unable to parse link"): + self.line = line + self.start = start + self.end = end + self.fragment = fragment + self.rest = rest + self.message = message + + def __str__(self): + if self.line is not None: + msg = [self.message] + msg.append(self.line) + err_line = ['^'.rjust(self.start + 1, ' ')] + err_line += [''.join(['~' for x in range(self.end - self.start - 1)])] + msg.append("".join(err_line)) + return "\n".join(msg) + else: + return f"{self.message}: [{self.fragment}@{self.rest}]" + + +class LinkGenerator: + def __init__(self, **kwargs): + self._line = kwargs.get('line') + self._start = kwargs.get('start', 0) + self._end = kwargs.get('end', 0) + self._namespace = kwargs.get('namespace') + self._fragment = kwargs.get('fragment', '') + self._endpoint = kwargs.get('endpoint', '') + self._no_link = kwargs.get('no_link', False) ++ self._alt_text = kwargs.get('text') + + assert self._namespace is not None + + self._repository = self._namespace.repository + self._valid_namespaces = [n for n in self._repository.includes] + self._external = False + + fragment_parsers = { + "alias": self._parse_type, + "callback": self._parse_type, + "class": self._parse_type, + "const": self._parse_type, + "ctor": self._parse_method, + "enum": self._parse_type, + "error": self._parse_type, + "flags": self._parse_type, + "func": self._parse_func, + "id": self._parse_id, + "iface": self._parse_type, + "method": self._parse_method, + "property": self._parse_property, + "signal": self._parse_signal, + "struct": self._parse_type, + "type": self._parse_type, + "vfunc": self._parse_method, + } + + parser_method = fragment_parsers.get(self._fragment) + if parser_method is not None: + res = parser_method(self._fragment) + if res is not None: + self._fragment = None + log.warning(str(res)) + else: + self._fragment = None + log.warning(str(LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + "Unable to parse link"))) + + def _parse_id(self, fragment): - t = self._namespace.find_symbol(self._endpoint) ++ symbol = self._repository.find_symbol(self._endpoint) ++ if symbol is None: ++ return LinkParseError(self._line, self._start, self._end, ++ self._fragment, self._endpoint, ++ f"Unable to find symbol {self._endpoint}") ++ (ns, t) = symbol + if isinstance(t, gir.Class) or \ + isinstance(t, gir.Interface) or \ + isinstance(t, gir.Record): ++ self._external = ns is not self._namespace ++ self._ns = ns.name + self._fragment = 'method' + self._symbol_name = f"{self._endpoint}()" + self._name = t.name - self._method_name = self._endpoint.replace(self._namespace.symbol_prefix[0] + '_', '') ++ self._method_name = self._endpoint.replace(ns.symbol_prefix[0] + '_', '') + self._method_name = self._method_name.replace(t.symbol_prefix + '_', '') + return None + elif isinstance(t, gir.Function): ++ self._external = ns is not self._namespace ++ self._ns = ns.name + self._fragment = 'func' + self._symbol_name = f"{self._endpoint}()" + self._name = None - self._func_name = self._endpoint.replace(self._namespace.symbol_prefix[0] + '_', '') ++ self._func_name = self._endpoint.replace(ns.symbol_prefix[0] + '_', '') + return None + else: + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, - f"Unable to find symbol {self._endpoint}") ++ f"Unsupported symbol {self._endpoint}") + + def _parse_type(self, fragment): + res = TYPE_RE.match(self._endpoint) + if res: + ns = res.group('ns') + name = res.group('name') + if ns is not None: + ns = ns[:len(ns) - 1] # Drop the trailing dot + else: + ns = self._namespace.name + # Accept FooBar in place of Foo.Bar + if name.startswith(tuple(self._namespace.identifier_prefix)): + for prefix in self._namespace.identifier_prefix: + name = name.replace(prefix, '') + else: + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + "Invalid type link") + if ns == self._namespace.name: + namespace = self._namespace + self._external = False + self._ns = ns + else: + repository = self._namespace.repository + namespace = repository.find_included_namespace(ns) + if namespace is not None: + self._external = True + self._ns = namespace.name + else: + self._fragment = None + return None + t = namespace.find_real_type(name) + if t is not None and t.base_ctype is not None: + if fragment == 'type': + if isinstance(t, gir.Alias): + self._fragment = 'alias' + elif isinstance(t, gir.BitField): + self._fragment = 'flags' + elif isinstance(t, gir.Callback): + self._fragment = 'callback' + elif isinstance(t, gir.Class): + self._fragment = 'class' + elif isinstance(t, gir.Constant): + self._fragment = 'const' + elif isinstance(t, gir.Enumeration): + self._fragment = 'enum' + elif isinstance(t, gir.ErrorDomain): + self._fragment = 'error' + elif isinstance(t, gir.Interface): + self._fragment = 'iface' + elif isinstance(t, gir.Record) or isinstance(t, gir.Union): + self._fragment = 'struct' + else: + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + f"Invalid type {t} for '{ns}.{name}'") + self._name = name + self._type = t.base_ctype + return None + else: + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + f"Unable to find type '{ns}.{name}'") + + def _parse_property(self, fragment): + res = PROPERTY_RE.match(self._endpoint) + if res: + ns = res.group('ns') + name = res.group('name') + pname = res.group('property') + if ns is not None: + ns = ns[:len(ns) - 1] # Drop the trailing dot + else: + ns = self._namespace.name + # Accept FooBar in place of Foo.Bar + if name.startswith(tuple(self._namespace.identifier_prefix)): + for prefix in self._namespace.identifier_prefix: + name = name.replace(prefix, '') + # Canonicalize the property name + pname = pname.replace('_', '-') + else: + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + "Invalid property link") + if ns == self._namespace.name: + namespace = self._namespace + self._external = False + self._ns = ns + else: + repository = self._namespace.repository + namespace = repository.find_included_namespace(ns) + if namespace is not None: + self._external = True + self._ns = ns + else: + self._fragment = None + return None + t = namespace.find_real_type(name) + if t is not None and t.base_ctype is not None: + self._type = t.base_ctype + self._name = name + else: + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + f"Unable to find type '{ns}.{name}'") + if (isinstance(t, gir.Class) or isinstance(t, gir.Interface)) and pname in t.properties: + self._property_name = pname + else: + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + f"Invalid property '{pname}' for type '{ns}.{name}'") + + def _parse_signal(self, fragment): + res = SIGNAL_RE.match(self._endpoint) + if res: + ns = res.group('ns') + name = res.group('name') + sname = res.group('signal') + if ns is not None: + ns = ns[:len(ns) - 1] # Drop the trailing dot + else: + ns = self._namespace.name + # Accept FooBar in place of Foo.Bar + if name.startswith(tuple(self._namespace.identifier_prefix)): + for prefix in self._namespace.identifier_prefix: + name = name.replace(prefix, '') + # Canonicalize the signal name + sname = sname.replace('_', '-') + else: + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + "Invalid signal link") + if ns == self._namespace.name: + namespace = self._namespace + self._external = False + self._ns = ns + else: + repository = self._namespace.repository + namespace = repository.find_included_namespace(ns) + if namespace is not None: + self._external = True + self._ns = namespace.name + else: + self._fragment = None + return None + t = namespace.find_real_type(name) + if t is not None and t.base_ctype is not None: + self._type = t.base_ctype + self._name = name + else: + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + f"Unable to find type '{ns}.{name}'") + if (isinstance(t, gir.Class) or isinstance(t, gir.Interface)) and sname in t.signals: + self._signal_name = sname + else: + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + f"Invalid signal name '{sname}' for type '{ns}.{name}'") + + def _parse_method(self, fragment): + res = METHOD_RE.match(self._endpoint) + if res: + ns = res.group('ns') + name = res.group('name') + method = res.group('method') + if ns is not None: + ns = ns[:len(ns) - 1] # Drop the trailing dot + else: + ns = self._namespace.name + # Accept FooBar in place of Foo.Bar + if name.startswith(tuple(self._namespace.identifier_prefix)): + for prefix in self._namespace.identifier_prefix: + name = name.replace(prefix, '') + else: + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + "Invalid method link") + if ns == self._namespace.name: + namespace = self._namespace + self._external = False + self._ns = ns + else: + repository = self._namespace.repository + namespace = repository.find_included_namespace(ns) + if namespace is not None: + self._ns = namespace.name + self._external = True + else: + self._fragment = None + return None + t = namespace.find_real_type(name) + if t is not None and t.base_ctype is not None: + self._type = t.base_ctype + self._method_name = method + # method@Foo.BarClass.add_name -> class_method.Bar.add_name.html + if isinstance(t, gir.Record) and t.struct_for is not None: + self._name = t.struct_for + self._fragment = "class_method" + elif fragment == "vfunc" and t.type_struct is not None: + self._name = name + self._type = t.type_struct + else: + self._name = name + else: + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + f"Unable to find type '{ns}.{name}'") + if fragment == "ctor": + methods = getattr(t, "constructors", []) + elif fragment in ["method", "class_method"]: + methods = getattr(t, "methods", []) + elif fragment == "vfunc": + methods = getattr(t, "virtual_methods", []) + else: + methods = [] + for m in methods: + if m.name == method: + if fragment == "vfunc": + self._vfunc_name = m.name + else: + self._symbol_name = f"{m.identifier}()" + return None + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + f"Unable to find method '{ns}.{name}.{method}'") + + def _parse_func(self, fragment): + tokens = self._endpoint.split('.') + # Case 1: [func@init] => gtk_init() + if len(tokens) == 1: + ns = self._namespace.name + name = None + func_name = tokens[0] + # Case 2: [func@Gtk.Foo.bar] => gtk_foo_bar() + elif len(tokens) == 3: + ns = tokens[0] + name = tokens[1] + func_name = tokens[2] + # Case 3: either [func@Gtk.init] or [func@Foo.bar] + elif len(tokens) == 2: + if tokens[0] == self._namespace.name: + ns = tokens[0] + name = None + func_name = tokens[1] + elif tokens[0] in self._valid_namespaces: + ns = tokens[0] + name = None + func_name = tokens[1] + else: + ns = self._namespace.name + name = tokens[0] + func_name = tokens[1] + else: + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + "Invalid function link") + if ns == self._namespace.name: + namespace = self._namespace + self._external = False + self._ns = ns + else: + repository = self._namespace.repository + namespace = repository.find_included_namespace(ns) + if namespace is not None: + self._external = True + self._ns = namespace.name + else: + self._fragment = None + log.warning(f"Namespace {ns} not found for link {self._endpoint}") + return None + if name is None: + t = namespace.find_function(func_name) + if t is not None: + self._name = None + self._func_name = func_name + self._symbol_name = f"{t.identifier}()" + return None + else: + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + f"Unable to find function '{ns}.{func_name}'") + else: + t = namespace.find_real_type(name) + if t is None: + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + f"Unable to find type '{ns}.{name}'") + for func in t.functions: + if func.name == func_name: + self._name = name + self._func_name = func.name + self._symbol_name = f"{func.identifier}()" + return None + return LinkParseError(self._line, self._start, self._end, + self._fragment, self._endpoint, + f"Unable to find function '{ns}.{name}.{func_name}'") + + @property + def text(self): - if self._fragment in ['alias', 'class', 'const', 'enum', 'error', 'flags', 'iface', 'struct']: ++ if self._alt_text is not None: ++ return self._alt_text[1:len(self._alt_text) - 1] ++ elif self._fragment in ['alias', 'class', 'const', 'enum', 'error', 'flags', 'iface', 'struct']: + return f"{self._type}" + elif self._fragment == 'property': + return f"{self._type}:{self._property_name}" + elif self._fragment == 'signal': + return f"{self._type}::{self._signal_name}" + elif self._fragment in ['ctor', 'func', 'method', 'class_method']: - return f"{self._symbol_name}" ++ return f"{self._symbol_name}" + elif self._fragment == 'vfunc': + return f"{self._ns}.{self._type}.{self._vfunc_name}" + else: + return f"{self._endpoint}" + + @property + def href(self): + if self._fragment in ['alias', 'class', 'const', 'enum', 'error', 'flags', 'iface', 'struct']: + return f"{self._fragment}.{self._name}.html" + elif self._fragment == 'property': + return f"property.{self._name}.{self._property_name}.html" + elif self._fragment == 'signal': + return f"signal.{self._name}.{self._signal_name}.html" + elif self._fragment in ['ctor', 'method', 'class_method', 'vfunc']: + return f"{self._fragment}.{self._name}.{self._method_name}.html" + elif self._fragment == 'func': + if self._name is not None: + return f"type_func.{self._name}.{self._func_name}.html" + else: + return f"func.{self._func_name}.html" + else: + return None + + def __str__(self): + text = self.text + if self._no_link: + return text + link = self.href + if link is None: + return text + if self._external: + data_namespace = f"data-namespace=\"{self._ns}\"" + data_link = f"data-link=\"{link}\"" + href = "href=\"javascript:void(0)\"" + css = "class=\"external\"" + return f"{text}" + else: + return f"{text}" + + +def preprocess_docs(text, namespace, summary=False, md=None, extensions=[], plain=False, max_length=10): + if plain: + text = text.replace('\n', ' ') + text = re.sub(r'<[^<]+?>', '', text) + if max_length > 0: + words = text.split(' ') + if len(words) > max_length: + words = words[:max_length - 1] + words.append('...') + text = ' '.join(words) + return text + + processed_text = [] + + code_block_text = [] + code_block_language = None + inside_code_block = False + + for line in text.split("\n"): + # If we're in "summary" mode, we bail out at the first empty line + # after a paragraph + if summary and line == '' and len(processed_text) > 0: + break + + res = CODEBLOCK_START_RE.match(line) + if res: + code_block_language = process_language(res.group("language")) + inside_code_block = True + continue + + res = CODEBLOCK_END_RE.match(line) + if res and inside_code_block: + if code_block_language == "plain": + processed_text += ["```"] + processed_text.extend(code_block_text) + processed_text += ["```"] + else: + lexer = get_lexer_by_name(code_block_language) + formatter = HtmlFormatter() + code_block = highlight("\n".join(code_block_text), lexer, formatter) + processed_text += [""] + processed_text.extend(code_block.split("\n")) + processed_text += [""] + + code_block_language = None + code_block_text = [] + inside_code_block = False + continue + + if inside_code_block: + code_block_text.append(line) + else: + new_line = [] + idx = 0 + for m in LINK_RE.finditer(line, idx): + fragment = m.group('fragment') + endpoint = m.group('endpoint') ++ text = m.group('text') + start = m.start() + end = m.end() + link = LinkGenerator(line=line, start=start, end=end, + namespace=namespace, + fragment=fragment, endpoint=endpoint, - no_link=summary) ++ no_link=summary, text=text) + left_pad = line[idx:start] + replacement = re.sub(LINK_RE, str(link), line[start:end]) + new_line.append(left_pad) + new_line.append(replacement) + idx = end + new_line.append(line[idx:]) + + if len(new_line) == 0: + processed_text.append(line) + else: + processed_text.append("".join(new_line)) + + if len(processed_text) == 0: + return '' + + # Capitalize the first character of the first line, but only if it does not + # start with a link or a gtk-doc marker, to avoid messing up the rest of + # the string + first_line = processed_text[0] + if first_line and first_line[0].isalpha(): + processed_text[0] = ''.join([first_line[0:1].upper(), first_line[1:]]) + + # Append a period, if one isn't there already + last_line = processed_text[-1] - if last_line and last_line[-1] != '.': ++ if last_line and last_line[-1].isalpha(): + processed_text[-1] = ''.join([last_line, '.']) + + if md is None: + md_ext = extensions.copy() + md_ext.extend(MD_EXTENSIONS) + text = markdown.markdown("\n".join(processed_text), + extensions=md_ext, + extension_configs=MD_EXTENSIONS_CONF) + else: + text = md.reset().convert("\n".join(processed_text)) + + return Markup(typogrify(text, ignore_tags=['h1', 'h2', 'h3', 'h4'])) + + +def stem(word, stemmer=None): + if stemmer is None: + stemmer = porter.PorterStemmer() + return stemmer.stem(word, 0, len(word) - 1) + + +def index_description(text, stemmer=None): + processed_text = [] + + inside_code_block = False + for line in text.split("\n"): + if not inside_code_block and (line.startswith('```') or line.startswith('|[')): + inside_code_block = True + continue + + if inside_code_block and (line.startswith('```') or line.startswith(']|')): + inside_code_block = False + continue + + if not inside_code_block: + processed_text.append(line) + + data = " ".join(processed_text) + terms = set() + for chunk in data.split(" "): + chunk = chunk.lower() + if chunk in ["\n", "\r", "\r\n"]: + continue + # Skip gtk-doc sygils + if chunk.startswith('%') or chunk.startswith('#') or chunk.startswith('@') or chunk.endswith('()'): + continue + # Skip gi-docgen links + if chunk.startswith('[') and chunk.endswith(']') and '@' in chunk: + continue + # Skip images + if chunk.startswith('!['): + continue + if chunk in EN_STOPWORDS: + continue + chunk = re.sub(r"`(\w+)`", r"\g<1>", chunk) + chunk = re.sub(r"[,\.:;`]$", '', chunk) + chunk = re.sub(r"[\(\)]+", '', chunk) + terms.add(stem(chunk, stemmer)) + return terms + + +def canonicalize(symbol): + return symbol.replace('-', '_') + + +def index_identifier(symbol, stemmer=None): + """Chunks an identifier (e.g. EventControllerClik) into terms useful for indexing.""" + symbol = re.sub(CAMEL_CASE_START_RE, r"\g<1>_\g<2>", symbol) + symbol = re.sub(CAMEL_CASE_CHUNK_RE, r"\g<1>_\g<2>", symbol) + symbol = symbol.replace('-', '_') + symbol = symbol.lower() + terms = set() + for chunk in symbol.split('_'): + if chunk in EN_STOPWORDS: + continue + terms.add(stem(chunk, stemmer)) + return terms + + +def index_symbol(symbol, stemmer=None): + """Chunks a symbol (e.g. set_layout_manager) into terms useful for indexing.""" + terms = set() + for chunk in canonicalize(symbol).split('_'): + if chunk in EN_STOPWORDS: + continue + terms.add(stem(chunk, stemmer)) + return terms + + +def code_highlight(text, language='c'): + lexer = get_lexer_by_name(language) + formatter = HtmlFormatter() + return Markup(highlight(text, lexer, formatter)) + + +def render_dot(dot, output_format="svg"): + if output_format not in ["svg", "png"]: + log.error("Invalid output format for render_dot(): {output_format}") + + args = ["dot", f"-T{output_format}"] + + try: + proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + proc.stdin.write(dot.encode("utf-8")) + output, err = proc.communicate() + if err: + log.warning(f"Unable to process dot data: {err}") + return None + if output_format == "svg": + return output.decode("utf-8") + except Exception as e: + log.warning(f"Unable to process dot data: {e}") + return None + + +found_programs = {} + + +def find_program(bin_name, path=None): + """Finds a program @bin_name inside the given @path, and returns + its full path if found, or None if the program could not be found. + + The @bin_name will automatically get an extension depending on the + platform. + """ + global found_programs + + if path is None and bin_name in found_programs: + return found_programs[bin_name] + + if path is None: + search_paths = os.environ['PATH'].split(os.pathsep) + else: + search_paths = path.split(os.pathsep) + + bin_extensions = [''] + + if sys.platform == 'win32': + pathext = os.environ['PATHEXT'].lower().split(os.pathsep) + (basename, extension) = os.path.splitext(bin_name) + if extension.lower() not in pathext: + bin_extensions = pathext + search_paths.insert(0, '') + + for ext in bin_extensions: + executable = bin_name + ext + + for p in search_paths: + full_path = os.path.join(p, executable) + if os.path.isfile(full_path): + # Memoize the result with the default PATH, so we can + # call this multiple times at no additional cost + if path is None: + found_programs[bin_name] = full_path + return full_path + + return None + + +def default_search_paths(): + if not sys.platform == 'win32': + xdg_data_dirs = os.environ.get("XDG_DATA_DIRS", "/usr/share:/usr/local/share").split(":") + xdg_data_home = os.environ.get("XDG_DATA_HOME", os.path.expanduser("~/.local/share")) + else: + xdg_data_dirs = None + xdg_data_home = None + + paths = [] + paths.append(os.getcwd()) + # Add sys.base_prefix when using MSYS2 + if sys.platform == 'win32' and 'GCC' in sys.version: + paths.append(os.path.join(sys.base_prefix, 'share', 'gir-1.0')) + if xdg_data_home is not None: + paths.append(os.path.join(xdg_data_home, "gir-1.0")) + if xdg_data_dirs is not None: + paths.extend([os.path.join(x, "gir-1.0") for x in xdg_data_dirs]) + + return paths ++ ++ ++def find_extra_content_file(content_dirs, file): ++ for p in content_dirs: ++ full_path = os.path.join(p, file) ++ if os.path.isfile(full_path): ++ return full_path ++ ++ raise FileNotFoundError(f"Content file {file} not found in any content directory") diff --cc subprojects/gi-docgen/meson.build index 28b73e7a42,0000000000..62c4de2187 mode 100644,000000..100644 --- a/subprojects/gi-docgen/meson.build +++ b/subprojects/gi-docgen/meson.build @@@ -1,71 -1,0 +1,72 @@@ +# SPDX-FileCopyrightText: 2021 GNOME Foundation +# +# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later + +project('gi-docgen', - version: '2021.6', ++ version: '2021.9', + meson_version: '>= 0.55.0', +) + +py = import('python').find_installation('python3', + modules: [ + 'jinja2', + 'markdown', + 'markupsafe', + 'pygments', + 'toml', + 'typogrify', + ], +) + +configure_file( + input: 'gi-docgen.py', + output: 'gi-docgen', + copy: true, + install: not meson.is_subproject(), + install_dir: get_option('bindir'), +) + +# When using gi-docgen as a sub-project +dummy_dep = declare_dependency() +meson.override_find_program('gi-docgen', find_program('gi-docgen.py')) + +pkgconf = configuration_data() +pkgconf.set('VERSION', meson.project_version()) +configure_file( + input: 'gi-docgen.pc.in', + output: 'gi-docgen.pc', + configuration: pkgconf, + install: not meson.is_subproject(), + install_dir: get_option('datadir') / 'pkgconfig', +) + +if not meson.is_subproject() + install_subdir('gidocgen', install_dir: py.get_install_dir()) +endif + +# Development tests should not be run when in a subproject +if get_option('development_tests') and not meson.is_subproject() + flake8 = find_program('flake8', required: false) + if flake8.found() + test('flake8', + flake8, + args: [ + '--show-source', + meson.current_source_dir() / 'gidocgen', + ], + ) + endif + - mypy = find_program('mypy', required: false) - if mypy.found() - test('mypy', - mypy, - args: [ - '--ignore-missing-imports', - '--disallow-incomplete-defs', - meson.current_source_dir() / 'gidocgen', - ], - ) - endif ++# mypy = find_program('mypy', required: false) ++# if mypy.found() ++# test('mypy', ++# mypy, ++# args: [ ++# '--ignore-missing-imports', ++# '--disallow-incomplete-defs', ++# meson.current_source_dir() / 'gidocgen', ++# ], ++# should_fail: true, ++# ) ++# endif +endif