diff --git a/.gitignore b/.gitignore index 8f66827a0f..b0cb671fde 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +data/theme/cinnamon.css debian/*.debhelper debian/*.log debian/*.substvars diff --git a/data/meson.build b/data/meson.build index f46bf967fb..ca1b61117b 100644 --- a/data/meson.build +++ b/data/meson.build @@ -5,9 +5,16 @@ install_subdir( install_dir: pkgdatadir, ) +subdir('theme') + install_subdir( 'theme', - exclude_files: ['theme-changelog.txt'], + exclude_files: [ + 'theme-changelog.txt', + 'meson.build', + 'parse-sass.sh' + ], + exclude_directories: ['cinnamon-sass'], install_dir: pkgdatadir, ) diff --git a/data/org.cinnamon.gschema.xml b/data/org.cinnamon.gschema.xml index edd5104a50..db44b49bfd 100644 --- a/data/org.cinnamon.gschema.xml +++ b/data/org.cinnamon.gschema.xml @@ -484,13 +484,9 @@ Aliases for use in the Alt-F2 dialog. This is a list of strings of the form a:b, where an instance of "a" is to be replaced with "b". Replacement is only performed on the first word. - - "medium" - Whether the media keys osd is disabled or its relative display size - - Allows setting of the default size of the media keys osd or disables it completely. - Possible values are "small", "medium", "large", or "disabled". - + + true + Whether or not to show the media keys osd diff --git a/data/theme/add-workspace-hover.png b/data/theme/add-workspace-hover.png deleted file mode 100644 index 129bad2b09..0000000000 Binary files a/data/theme/add-workspace-hover.png and /dev/null differ diff --git a/data/theme/add-workspace-hover.svg b/data/theme/add-workspace-hover.svg new file mode 100644 index 0000000000..adbf1f5aee --- /dev/null +++ b/data/theme/add-workspace-hover.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/data/theme/add-workspace.png b/data/theme/add-workspace.png deleted file mode 100644 index 0b70195550..0000000000 Binary files a/data/theme/add-workspace.png and /dev/null differ diff --git a/data/theme/add-workspace.svg b/data/theme/add-workspace.svg new file mode 100644 index 0000000000..3f05aa32cb --- /dev/null +++ b/data/theme/add-workspace.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/data/theme/calendar-arrow-left-hover.svg b/data/theme/calendar-arrow-left-hover.svg new file mode 100644 index 0000000000..261a0833cf --- /dev/null +++ b/data/theme/calendar-arrow-left-hover.svg @@ -0,0 +1,155 @@ + + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + + diff --git a/data/theme/calendar-arrow-left.svg b/data/theme/calendar-arrow-left.svg index 54a9f2d057..27742545b2 100644 --- a/data/theme/calendar-arrow-left.svg +++ b/data/theme/calendar-arrow-left.svg @@ -1,4 +1,152 @@ - - + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + diff --git a/data/theme/calendar-arrow-right-hover.svg b/data/theme/calendar-arrow-right-hover.svg new file mode 100644 index 0000000000..3647ca0abd --- /dev/null +++ b/data/theme/calendar-arrow-right-hover.svg @@ -0,0 +1,155 @@ + + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + + diff --git a/data/theme/calendar-arrow-right.svg b/data/theme/calendar-arrow-right.svg index 8d9047bed0..366e69b10d 100644 --- a/data/theme/calendar-arrow-right.svg +++ b/data/theme/calendar-arrow-right.svg @@ -1,4 +1,152 @@ - - + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + diff --git a/data/theme/calendar-selected.svg b/data/theme/calendar-selected.svg deleted file mode 100644 index 1b6fae15f2..0000000000 --- a/data/theme/calendar-selected.svg +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/data/theme/calendar-today-selected.svg b/data/theme/calendar-today-selected.svg deleted file mode 100644 index 10d72f368a..0000000000 --- a/data/theme/calendar-today-selected.svg +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/data/theme/calendar-today.svg b/data/theme/calendar-today.svg deleted file mode 100644 index c46bba14dc..0000000000 --- a/data/theme/calendar-today.svg +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/data/theme/checkbox-off.svg b/data/theme/checkbox-off.svg index b836f317f3..c4f9674c68 100644 --- a/data/theme/checkbox-off.svg +++ b/data/theme/checkbox-off.svg @@ -1,98 +1,48 @@ - - + id="svg1622" + sodipodi:docname="checkbox-off.svg" + inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> - - - - - - + id="defs1626" /> + inkscape:zoom="19.666667" + inkscape:cx="5.0084745" + inkscape:cy="10.474576" + inkscape:window-width="1471" + inkscape:window-height="748" + inkscape:window-x="134" + inkscape:window-y="95" + inkscape:window-maximized="0" + inkscape:current-layer="svg1622"> + id="grid841" + originx="0" + originy="0" /> - - - - image/svg+xml - - - - - - - - + diff --git a/data/theme/checkbox.svg b/data/theme/checkbox.svg index d7c9681d69..2159518535 100644 --- a/data/theme/checkbox.svg +++ b/data/theme/checkbox.svg @@ -1,104 +1,46 @@ - - + id="svg745" + sodipodi:docname="checkbox.svg" + inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> - - - - - - + id="defs749" /> - - - - - - image/svg+xml - - - - - - - - - + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + showgrid="false" + inkscape:zoom="19.666667" + inkscape:cx="6.8898304" + inkscape:cy="12.508474" + inkscape:window-width="1471" + inkscape:window-height="748" + inkscape:window-x="111" + inkscape:window-y="162" + inkscape:window-maximized="0" + inkscape:current-layer="svg745" /> + + diff --git a/data/theme/cinnamon-sass/_colors.scss b/data/theme/cinnamon-sass/_colors.scss new file mode 100644 index 0000000000..c9f18d40d4 --- /dev/null +++ b/data/theme/cinnamon-sass/_colors.scss @@ -0,0 +1,43 @@ +// global colors +$bg_color: #242424; +$base_color: #303030; +$fg_color: white; + +$panel_bg: #1a1a1a; + +// colored elements +$error_color: #e4705b; +$error_bg_color: #c01c28; + +$success_color: #8ff0a4; +$success_bg_color: #26a269; + +$destructive_bg_color: #c01c28; +$destructive_color: #ff7b63; + +$warning_color: #f8e45c; +$warning_bg_color: #cd9309; + +$accent_color: #78aeed; +$accent_bg_color: #3584e4; + +$large_icon_color: transparentize($fg_color, 0.6); +$light_text_color: mix($fg_color, $bg_color, 65%); + +// used for button, entries and highlighted items +$light_bg_color: #393939; +$light_base_color: #444444; +$lighter_bg_color: #454545; +$lightest_bg_color: #656565; + +// link colors +$link_color: #1c71d8; + +// borders +$borders_color: #333333; + +// shadows +$shadow_color: rgba(0, 0, 0, 0.5); + +// insensitive state +$insensitive_fg_color: mix($fg_color, $bg_color, 40%); diff --git a/data/theme/cinnamon-sass/_common.scss b/data/theme/cinnamon-sass/_common.scss new file mode 100644 index 0000000000..907b779d15 --- /dev/null +++ b/data/theme/cinnamon-sass/_common.scss @@ -0,0 +1,178 @@ +$base_padding: 6px; +$base_margin: 4px; +$base_border_radius: 8px; + +$modal_dialog_radius: 18px; + +$scalable_icon_size: to_em(16px); + +// stage +stage { + color: $fg_color; +} + +%entry_common { + min-height: 22px; + border-radius: $base_border_radius; + padding: $base_padding $base_padding * 1.5; + border: 1px solid $borders_color; + caret-color: $fg_color; + selected-color: black; + selection-background-color: $accent_bg_color; + caret-size: 1px; +} + +%button_common { + border-radius: $base_border_radius; + padding: $base_padding $base_padding * 6; + font-weight: bold; +} + +%button { + @extend %button_common; + @include button(normal); + &:focus { @include button(focus); } + &:hover { @include button(hover); } + &:active { @include button(active); } + &:insensitive { @include button(insensitive); } +} + +%flat_button { + @include button(normal, $style: flat); + &:focus { @include button(focus, $style: flat); } + &:hover { @include button(hover, $style: flat); } + &:insensitive { @include button(insensitive, $style: flat); } + &:selected, + &:active { @include button(active, $style: flat); } + &:checked { @include button(checked, $style: flat); } +} + +%entry { + @extend %entry_common; + @include entry(normal); + &:focus { @include entry(focus); } + &:insensitive { @include entry(insensitive); } + + StLabel.hint-text { color: transparentize($fg_color, 0.7); } + + .capslock-warning { icon-size: $scalable_icon_size; } +} + +// buttons in dialogs + +%dialog_button { + font-weight: bold; + padding: $base_padding * 2; + border-radius: $base_border_radius * 1.5; + + @include button(normal); + &:focus { @include button(focus); } + &:hover { @include button(hover); } + &:active { @include button(active); } + &:checked { @include button(checked); } + &:insensitive { @include button(insensitive); } +} + +%dialog_button_default { + @extend %dialog_button; + + @include button(normal, $c: $accent_bg_color, $style: default); + &:hover { @include button(hover, $c: $accent_bg_color, $style: default); } + &:active { @include button(active, $c: $accent_bg_color, $style: default); } + &:checked { @include button(checked, $c: $accent_bg_color, $style: default); } + &:insensitive { + border-color: $borders_color; + + @include button(insensitive); + } +} + +%dialog_button_destructive { + @extend %dialog_button; + + @include button(normal, $c: $error_bg_color, $style: default); + &:hover { @include button(hover, $c: $error_bg_color, $style: default); } + &:active { @include button(active, $c: $error_bg_color, $style: default); } + &:checked { @include button(checked, $c: $error_bg_color, $style: default); } + &:insensitive { + border-color: $borders_color; + + @include button(insensitive); + } +} + +// items in menus +%menuitem { + font-weight: normal; + spacing: $base_padding; + transition-duration: 100ms; + padding: $base_padding + 2 $base_padding * 2; + margin: 0 $base_margin; + border-radius: $base_border_radius; +} + +/* General Typography */ +%large_title { + font-weight: 300; + @include fontsize(24pt); +} + +%title_1 { + font-weight: 800; + @include fontsize(20pt); +} + +%title_2 { + font-weight: 800; + @include fontsize(15pt); +} + +%title_3 { + font-weight: 700; + @include fontsize(15pt); +} + +%title_4 { + font-weight: 700; + @include fontsize(13pt); +} + +%heading { + font-weight: 700; + @include fontsize(11pt); +} + +%caption_heading { + font-weight: 700; + @include fontsize(9pt); +} + +%caption { + font-weight: 400; + @include fontsize(9pt); +} + +%smaller { + font-weight: 400; + @include fontsize(8pt); +} + +%slider { + height: 1em; + min-width: 15em; + -slider-height: 0.3em; + -slider-background-color: $light_bg_color; + -slider-active-background-color: $fg_color; + -slider-border-color: transparent; + -slider-active-border-color: transparent; + -slider-border-width: 1px; + -slider-handle-radius: 0.5em; +} + +%osd_base { + background-color: transparentize($bg_color, 0.01); + border: 1px solid transparentize($borders_color, 0.01); + border-radius: $base_border_radius; + text-align: center; + padding: $base_padding * 4; +} diff --git a/data/theme/cinnamon-sass/_drawing.scss b/data/theme/cinnamon-sass/_drawing.scss new file mode 100644 index 0000000000..0304ec7628 --- /dev/null +++ b/data/theme/cinnamon-sass/_drawing.scss @@ -0,0 +1,135 @@ +// function to convert px to em +@function to_em($input, $base: 16px) { + // multiplied and divided by 1000 to make up for round() shortcoming + $em_value: ($input / $base) * 1.091 * 1000; + @return round($em_value) / 1000 * 1em; +} + +// Mixin to convert provided font size in pt to em units +@mixin fontsize($size, $base: 16px, $unit: pt) { + // if pt, convert into unitless value with the assumption: 1pt = 1.091px + $adjusted_size: if($unit == pt, $size * 1.091, $size) * 1000; + $rounded_size: round($adjusted_size / $base) / 1000; + font-size: $rounded_size * 1em; + // font-size: round($size) + pt; +} + +@mixin entry($type) { + // + // $type: entry type, possible values: normal, focus, hover, insensitive + // $c: text color + // $bc: background color + // + + $entry_fg_color: $fg_color; + $entry_bg_color: $light_bg_color; + + $insensitive_factor: 3%; + + $insensitive_entry_bg_color: darken($entry_bg_color, $insensitive_factor); + + // normal + @if $type == 'normal' { + background-color: $entry_bg_color; + color: $entry_fg_color; + } + + @if $type == 'focus' { + background-color: $entry_bg_color; + color: $entry_fg_color; + border-color: $accent_bg_color; + } + + @if $type == 'insensitive' { + background-color: $insensitive_entry_bg_color; + color: transparentize($entry_fg_color, 0.5); + } +} + +// Button drawing function +@mixin button($type, $tc:$fg_color, $c:$bg_color, $style: null) { + // + // $type: button type, possible values: + // - normal, focus, hover, active, checked, insensitive, default, undecorated + // $c: button bg color, derived from bg_color + // $tc: button text color, derived from fg_color + // $style: button style, possible values: flat, default + // + + // mix input colors to get button background color + $button_bg_color: $light_bg_color; + + // background color mix override for flat style; the button bg color is the background color input + @if $style == 'flat' { $button_bg_color: $c;} + // background color mix override for default button style + @if $style == 'default' { $button_bg_color: $c;} + + // background color adjustment factors + // the % a color is lightened or darkened for button states + $insensitive_factor: 3%; + + // button base state background colors + $hover_button_bg_color: $lighter_bg_color; + $active_button_bg_color: $lightest_bg_color; + $checked_button_bg_color: $lightest_bg_color; + $insensitive_button_bg_color: darken($button_bg_color, $insensitive_factor); + + // background color mix override for default button style + @if $style == 'default' { + $hover_button_bg_color: lighten($button_bg_color, 10%); + $active_button_bg_color: darken($button_bg_color, 5%); + $checked_button_bg_color: darken($button_bg_color, 5%); + } + + // flat style overrides + @if $style == 'flat' { + $insensitive_button_bg_color: $button_bg_color; + } + + // normal style + @if $type == 'normal' { + color: $tc; + background-color: $button_bg_color; + } + + @if $type == 'focus' { + color: $tc; + background-color: $button_bg_color; + } + + // hover button + @else if $type == 'hover' { + color: $tc; + background-color: $hover_button_bg_color; + } + + // active button + @else if $type == 'active' { + color: $tc; + background-color: $active_button_bg_color; + } + + // checked button + @else if $type == 'checked' { + color: $tc; + background-color: $checked_button_bg_color; + } + + // insensitive button + @else if $type == 'insensitive' { + $insensitive_button_fg_color: transparentize($tc, .5); + color: $insensitive_button_fg_color; + background-color: $insensitive_button_bg_color; + } + + // reset (unstyled button) + @else if $type == 'undecorated' { + background-color: transparent; + border-color: transparent; + box-shadow: none; + + &:insensitive { + background-color: transparent !important; + } + } +} diff --git a/data/theme/cinnamon-sass/_widgets.scss b/data/theme/cinnamon-sass/_widgets.scss new file mode 100644 index 0000000000..d83150a82f --- /dev/null +++ b/data/theme/cinnamon-sass/_widgets.scss @@ -0,0 +1,16 @@ +// Primary widgets +@import 'widgets/alttab'; +@import 'widgets/applets'; +@import 'widgets/base'; +@import 'widgets/calendar'; +@import 'widgets/desklet'; +@import 'widgets/dialogs'; +@import 'widgets/expo'; +@import 'widgets/keyboard'; +@import 'widgets/menus'; +@import 'widgets/notifications'; +@import 'widgets/osd'; +@import 'widgets/panel'; +@import 'widgets/startmenu'; +@import 'widgets/switch-check'; +@import 'widgets/windowlist'; diff --git a/data/theme/cinnamon-sass/cinnamon.scss b/data/theme/cinnamon-sass/cinnamon.scss new file mode 100644 index 0000000000..e72eedd586 --- /dev/null +++ b/data/theme/cinnamon-sass/cinnamon.scss @@ -0,0 +1,4 @@ +@import "_colors"; +@import "_drawing"; +@import "_common"; +@import "_widgets"; diff --git a/data/theme/cinnamon-sass/widgets/_alttab.scss b/data/theme/cinnamon-sass/widgets/_alttab.scss new file mode 100644 index 0000000000..b92d8c35d0 --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_alttab.scss @@ -0,0 +1,70 @@ +#altTabPopup { + padding: $base_margin * 2; + spacing: $base_margin * 4; +} + +.switcher-list { + background-color: $panel_bg; + border: 1px solid $borders_color; + border-radius: $base_border_radius * 2; + box-shadow: 0 0 6px 0 $shadow_color; + padding: $base_padding * 3; + + &-item-container { spacing: $base_margin * 3; } + + .item-box { + padding: $base_margin * 2; + border: 1px solid transparent; + border-radius: $base_border_radius; + background-color: transparent; + + // this doesn't ever seem to get used + &:outlined { border-color: red; } + &:selected { + border-color: $borders_color; + background-color: $light_bg_color + } + } + + .thumbnail-box { + padding: 0; + spacing: $base_margin; + } + + .thumbnail { width: 256px; } + + .separator {} +} + +.switcher-preview-backdrop { background-color: transparentize(black, 0.5); } + +.switcher-arrow { + background-color: transparent; + border-color: transparent; + color: $fg_color; + + &:highlighted {} +} + +.thumbnail-scroll-gradient { + + &-left { + background-gradient-direction: horizontal; + background-gradient-start: transparentize($panel_bg, 0.0); + background-gradient-end: transparentize($panel_bg, 1.0); + border-radius: $base_border_radius * 2; + border-radius-topright: 0px; + border-radius-bottomright: 0px; + width: 60px; + } + + &-right { + background-gradient-direction: horizontal; + background-gradient-start: transparentize($panel_bg, 1.0); + background-gradient-end: transparentize($panel_bg, 0.0); + border-radius: $base_border_radius * 2; + border-radius-topleft: 0px; + border-radius-bottomleft: 0px; + width: 60px; + } +} diff --git a/data/theme/cinnamon-sass/widgets/_applets.scss b/data/theme/cinnamon-sass/widgets/_applets.scss new file mode 100644 index 0000000000..2b94083b71 --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_applets.scss @@ -0,0 +1,233 @@ +$applet_separator: transparentize($fg_color, 0.8); + +//padding and spacing for applets +$applet_padding: 6px; + +.applet { + + &-box { + padding: 0 $applet_padding; + spacing: $applet_padding; + text-align: center; + + &.vertical { padding: $applet_padding 0; } + + &:hover { + background-color: $lighter_bg_color; + } + + &:highlight { background-color: transparentize($error_bg_color, 0.5); } + } + + &-label { font-weight: bold; } + + &-separator { + padding: 1px 4px; + + &.vertical { padding: 4px 1px; } + } + + &-separator-line { + width: 1px; + background: $applet_separator; + + &-vertical { + height: 1px; + background: $applet_separator; + } + } +} + +// cornerbar applet + +.applet-cornerbar { + width: $base_margin * 2; + background-color: $lighter_bg_color; + border: 1px solid $borders_color; + + &.vertical { height: $base_margin * 2; } + + &-box { + background: none; + } +} + +.applet-cornerbar-box:hover > .applet-cornerbar { background-color: $lightest_bg_color; } + + +// notification applet + +.notification-applet-padding { + padding: $base_margin 0 $base_margin $base_margin; +} + +// panel launchers + +.panel-launchers { + // padding-left: $base_padding; + spacing: 2px; + + .launcher { + padding: 0 2px; + + &:hover { background-color: $lighter_bg_color; } + } + + &.vertical { + padding: 2px 0; + + .launcher { padding: 2px 0; } + } +} + +// power applet + +.device-box { + + .device-icon { + icon-size: to_em(24px); + color: $fg_color; + } + + .device-labels { + margin-left: $base_margin * 2; + spacing: $base_margin; + + .primary-label { + @extend %heading; + + color: $fg_color; + } + + .status-label { color: $light_text_color; } + } +} + +// sound applet + +.sound-player { + + > StBoxLayout:first-child { + spacing: $base_margin; + padding: 0 $base_padding; + } + + StButton { + @extend %button; + + width: 18px; + height: 18px; + padding: $base_padding; + + + StIcon { icon-size: 1em; } + + &:small { + @extend %flat_button; + width: 16px; + height: 16px; + + StIcon { icon-size: 1.2 em;} + } + } + + &-generic-coverart { background-color: transparentize(black, 0.8); } + + &-overlay { + width: 290px; + padding: $base_padding * 2; + spacing: $base_margin; + background-color: transparentize($bg_color, 0.1); + + StBoxLayout { padding-top: 2px; } + > StBoxLayout { spacing: $base_padding; } + StBin > StBoxLayout { spacing: $base_padding; } + } + + .slider { + height: $base_padding; + -slider-height: $base_padding; + -slider-background-color: darken($base_color, 5%); + -slider-active-background-color: $fg_color; + -slider-border-color: transparent; + -slider-active-border-color: transparent; + -slider-border-width: 0; + -slider-handle-radius: 0; + } +} + +// spacer applet + +.spacer-box { + border: 1px solid transparent; + + &:highlight { background-color: $error_color; } + + &.edit-mode { border: 1px symbolic; } +} + +// systray + +.systray { + padding: 0; +} + +// workspace switcher applet + +.panel-top, +.panel-bottom { + + .workspace-switcher { padding: 0 $base_margin;} +} + +.workspace-button { + border: 1px solid $borders_color; + width: 2em; + color: $insensitive_fg_color; + background-color: transparentize($fg_color, 0.95); + + &.vertical { height: 2em; } + + &:outlined { + background-color: $light_bg_color; + color: $fg_color; + + &:hover { background-color: $lighter_bg_color; } + } + + &:hover { background-color: $light_bg_color; } + + &:shaded { // this is a workspace with no open windows + background-color: darken($bg_color, 5%); + } +} + +.workspace-graph { + padding: $base_margin; + spacing: $base_margin; + + .workspace { + border: 1px solid transparentize($fg_color, 0.8); + background-color: darken($panel_bg, 5%); + + &:active { + border-color: transparentize($fg_color, 0.5); + + .windows { + -active-window-background: transparentize(white, 0.7); + -active-window-border: transparentize(white, 0.65); + -inactive-window-background: transparentize(white, 0.9); + -inactive-window-border: transparentize(white, 0.85); + } + } + + .windows { + -active-window-background: transparentize(white, 0.7); + -active-window-border: transparentize(white, 0.65); + -inactive-window-background: transparentize(white, 0.9); + -inactive-window-border: transparentize(white, 0.85); + } + } +} + +.system-status-icon { icon-size: $scalable_icon-size; } diff --git a/data/theme/cinnamon-sass/widgets/_base.scss b/data/theme/cinnamon-sass/widgets/_base.scss new file mode 100644 index 0000000000..cd80f4f4ac --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_base.scss @@ -0,0 +1,139 @@ +.flashspot { background-color: white; } + +// links +.cinnamon-link { + color: $link_color; + + &:hover { + color: lighten($link_color, 10%); + } +} + +// lightbox + +.lightbox { background-color: rgba(0, 0, 0, 0.4); } + +// looking glass dialog + +#LookingGlassDialog { + @extend %osd_base; + + spacing: $base_margin; +} + +// magnifier + +.magnifier-zoom { + + &-region { + border: 2px solid $error_color; + + &.full-screen { border-width: 0; } + } +} + +// pie timer + +.pie-timer { + width: 30px; + height: 30px; + -pie-border-width: 1px; + -pie-border-color: rgba(200, 200, 200, 0.8); + -pie-background-color: rgba(140, 140, 140, 0.6); +} + +// ripples + +.ripple-pointer-location { + width: 50px; + height: 50px; + border-radius: 25px; + background-color: $accent_color; + box-shadow: 0 0 2px 2px rgba(160,160,160,1.0); +} + +.ripple-box { + width: 104px; + height: 104px; + background-image: url("corner-ripple.png"); + + &:rtl { background-image: url("corner-ripple.png"); } +} + +// scrollbars +StScrollView.vfade { -st-vfade-offset: 68px; } + +StScrollBar { + + StScrollView & { + min-height: 8px; + min-width: 8px; + } + + StBin#trough { + background-color: transparentize($base_color, 0.9); + border_radius: $base_border_radius; + } + + StButton#vhandle, + StButton#hhandle { + background-color: mix($fg_color, $bg_color, 30%); + border-radius: $base_border_radius; + + &:hover { background-color: mix($fg_color, $bg_color, 40%); } + &:active {} + } +} + +// separator + +.separator { + -gradient-height: 1px; + -gradient-start: $borders_color; + -gradient-end: $borders_color; + -margin-horizontal: 0; + height: 1px; +} + +// slider + +.slider { + @extend %slider; +} + +// tile previews + +.tile-preview { + background-color: transparentize($accent_color, 0.8); + border: 1px solid transparentize($accent_color, 0.3); +} + +#Tooltip { + @extend %osd_base; + + padding: $base_padding * 2; + margin: $base_margin; +} + +// user avatar + +.user-icon { + color: $fg_color; + border: none; + + &.user-avatar { + border: 1px solid transparentize($fg_color, 0.5); + border-radius: 99px; + } +} + +.user-widget-label {} + +.user-widget.horizontal { spacing: $base_padding; } + +.user-widget.vertical .user-widget-label { + @extend %title_4; + color: $fg_color; + padding-top: $base_margin * 2; + text-align: center; +} diff --git a/data/theme/cinnamon-sass/widgets/_calendar.scss b/data/theme/cinnamon-sass/widgets/_calendar.scss new file mode 100644 index 0000000000..dacaf57363 --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_calendar.scss @@ -0,0 +1,202 @@ +.calendar { + margin-top: $base_margin * 5; + spacing-rows: 2px; + spacing-columns: 2px; + + // can be used to set the entire bg color + &-background {} + + &-main-box { margin: $base_margin * 2; } + + &-events-main-box { + height: 300px; + margin-right: $base_margin * 4; + min-width: 350px; + border-right-width: 1px; + border-color: $borders_color; + } + + &-today-home-button, + &-today-home-button-enabled { + margin-left: $base_padding * 2; + + &:hover {} + } + + // the large date labels at the top + &-today-day-label { + @extend %title_4; + text-align: center; + } + + &-today-date-label { + @extend %title_3; + } + + &-month-label { + @extend %heading; + } + + &-change-month-back, + &-change-month-forward:rtl { + width: 16px; + height: 16px; + color: $fg_color; + background-image: url("calendar-arrow-left.svg"); + + &:hover { background-image: url("calendar-arrow-left-hover.svg"); } + } + + &-change-month-forward, + &-change-month-back:rtl { + width: 16px; + height: 16px; + color: $fg_color; + background-image: url("calendar-arrow-right.svg"); + + &:hover { background-image: url("calendar-arrow-right-hover.svg"); } + } + + &-day-event-dot-box { + margin-top: 1.7em; + max-rows: 1; + } + + &-day-event-dot { + margin: 1px; + border-radius: 2px; + width: 4px; + height: 4px; + } + + &-day-base { + text-align: center; + width: 2.4em; + height: 2.4em; + border-radius: 9999px; + color: $insensitive_fg_color; + + &:hover { + background-color: $lighter_bg_color; + } + } + + &-day-heading { + color: $fg_color; + margin-top: $base_margin * 3; + // using this to move the weekday row closer to the dates + height: 1.6em; + } + + &-work-day {} + &-week-number {} + &-work-day { color: $fg_color; } + &-nonwork-day { color: $fg_color; } + + &-today { + box-shadow: inset 0 0 3px $accent_bg_color; + background-color: $lightest_bg_color; + + &:hover { background-color: $lighter_bg_color; } + + &:selected {} + } + + &-other-month-day { + color: $insensitive_fg_color; + } + + &-not-today { + + &:selected { background-color: $light_bg_color; } + } + + // the calendar events area + &-events-date-label { + @extend %title_4; + text-align: center; + } + + &-events-no-events-box {} + + &-events-no-events-button { + margin: 6px 0; + padding: 6px; + border-radius: $base_border_radius; + color: $light_text_color; + + &:hover { color: $fg_color; } + } + + &-events-no-events-icon { + color: $large_icon_color; + icon-size: 128px; + } + + &-events-no-events-label { + @extend %title_3; + text-align: center; + margin-top: 16px; + } + + &-events-event-container {} + &-events-scrollbox { margin-top: $base_margin * 2;} + + &-events-main-box { + .separator { + -margin-horizontal: 1em; + -gradient-height: 1px; + -gradient-start: transparent; + -gradient-end: transparent; + } + } + + &-event-button { + margin: 3px 0; + border-radius: $base_border_radius; + border: 1px solid transparent; + + &:hover { + background-color: lighten($bg_color, 15%); + border-color: $borders_color; + } + } + + &-event-color-strip { width: 1px; } + + &-event-row-content { margin: 7px; } + + &-event-time-past { + @extend %heading; + color: $insensitive_fg_color; + } + + &-event-time-present { + @extend %heading; + color: $fg_color; + } + + &-event-time-present:all-day { + @extend %heading; + color: $accent_color; + } + + &-event-countdown { + @extend %caption; + + color: $light_text_color; + + &:soon { color: $warning_color; } + &:imminent { color: $error_color; } + &:current { color: $success_color; } + } + + &-event-time-future { + @extend %heading; + color: $fg_color; + } + + &-event-summary { + color: $light_text_color; + } +} diff --git a/data/theme/cinnamon-sass/widgets/_desklet.scss b/data/theme/cinnamon-sass/widgets/_desklet.scss new file mode 100644 index 0000000000..65b19b18ad --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_desklet.scss @@ -0,0 +1,46 @@ +// desklet + +.desklet { + &:highlight { + border: 2px solid $accent_color; + border-radius: $base_border_radius; + } + + &-with-borders { + border: 1px solid $borders_color; + border-radius: $base_border_radius; + background-color: transparentize($bg_color, 0.2); + } + + &-with-borders-and-header { + border: 1px solid $borders_color; + border-radius: 0 0 $base_border_radius $base_border_radius; + border-top-width: 0; + background-color: transparentize($bg_color, 0.2); + padding: $base_padding * 2; + } + + &-header { + border: 1px solid $borders_color; + border-radius: $base_border_radius $base_border_radius 0 0; + background-color: transparentize($bg_color, 0.2); + padding: $base_padding; + } + + &-drag-placeholder { + border: 1px solid red; + } +} + +// digital photo frame + +.photoframe-box { + border: 1px solid $borders_color; + border-radius: $base_border_radius; + background-color: transparentize($bg_color, 0.2); + padding: $base_padding; +} + +// clock + +.clock-desklet-label {} diff --git a/data/theme/cinnamon-sass/widgets/_dialogs.scss b/data/theme/cinnamon-sass/widgets/_dialogs.scss new file mode 100644 index 0000000000..976d1b946f --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_dialogs.scss @@ -0,0 +1,112 @@ +// Modal dialogs + +.dialog { + background-color: $bg_color; + border-radius: $modal_dialog_radius; + border: 1px solid $borders_color; + padding: $base_padding * 3; + + .dialog-content-box { + margin-top: $base_margin * 2; + margin-bottom: $base_margin * 4; + spacing: $base_margin * 8; + max-width: 28em; + } + + .dialog-button { + @extend %dialog_button; + + &:default { @extend %dialog_button_default; } + &:destructive-action { @extend %dialog_button_destructive; } + } + + .confirm-dialog-title { + @extend %title_2; + text-align: center; + } +} + +// message dialog + +.message-dialog-content { + spacing: $base_padding * 3; + + .message-dialog-title { + text-align: center; + @extend %title_2; + + &.leightweight { @extend %title_4; } + } + + .message-dialog-description { text-align: center; } +} + +// run dialog + +.run-dialog { + + .dialog-content-box { + margin: $base_margin; + } + + &-description { + @extend %caption; + + text-align: center; + color: darken($fg_color, 20%); + + &.error { color: $error_color; } + } + + &-completion-box { + padding-top: $base_padding; + padding-left: $base_padding * 2; + } + + &-entry { + @extend %entry; + + width: 20em; + height: 1.2em; + } +} + +// password or authentication dialog + +.prompt-dialog { + width: 28em; + + .dialog-content-box { + spacing: $base_margin * 4; + margin-bottom: $base_margin * 3; + } + + &-password-entry { + @extend %entry; + width: 20em; + } + + &-password-layout { spacing: $base_margin * 2;} + + &-error-label, + &-info-label, + &-null-label { + text-align: center; + @extend %caption; + } + + &-error-label { color: $error_color; } +} + +// polkit dialog + +.polkit-dialog { + + &-user-layout { + text-align: center; + spacing: $base_margin; + margin-bottom: $base_padding; + } + + &-user-root-label { color: $error_color; } +} diff --git a/data/theme/cinnamon-sass/widgets/_expo.scss b/data/theme/cinnamon-sass/widgets/_expo.scss new file mode 100644 index 0000000000..c5e51c7162 --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_expo.scss @@ -0,0 +1,91 @@ + +.workspace { + + &-thumbnails { spacing: 26px; } + &-thumbnails-background { padding: 8px; } + + // this controls both the darkness of thumbnails in expo and + // the darkness of the overiew backgroound + &-overview-background-shade { background-color: transparentize(black, 0.8); } + + &-add-button { + background-image: url("add-workspace.svg"); + height: 200px; + width: 35px; + transition-duration: 150; + + &:hover { + background-image: url("add-workspace-hover.svg"); + transition-duration: 150; + } + } + + &-close-button { + background-image: url("close.svg"); + height: 26px; + width: 26px; + -cinnamon-close-overlap: 13px; + } +} + +.expo { + + &-background { background-color: $bg_color; } + + &-workspace-thumbnail-frame { + border: 1px solid $borders_color; + + &#active { + border-color: $accent_color; + border-width: 2px; + } + } + + &-workspaces-name-entry { + @extend %entry; + + height: 1.5em; + + &#selected{} + &:focus {} + } +} + +.window { + + &-close-area { + background-image: url("trash-icon.svg"); + height: 120px; + width: 400px; + } + + &-close { + background-image: url("close.svg"); + height: 26px; + width: 26px; + -cinnamon-close-overlap: 13px; + + &:hover {} + } + + &-border { + border: 3px solid $accent_bg_color; + border-radius: $base_border_radius; + } + + &-caption { + min-height: 22px; + border-radius: $base_border_radius; + padding: $base_padding $base_padding * 1.5; + spacing: $base_margin; + border: 1px solid $borders_color; + background-color: $light_bg_color; + -cinnamon-caption-spacing: $base_padding; + + &:focus { background-color: $lightest_bg_color; } + } +} + +#overview { spacing: 12px; } + +.overview-empty-placeholder { @extend %large_title; } diff --git a/data/theme/cinnamon-sass/widgets/_keyboard.scss b/data/theme/cinnamon-sass/widgets/_keyboard.scss new file mode 100644 index 0000000000..36f2e0b5f9 --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_keyboard.scss @@ -0,0 +1,31 @@ +// on screen keyboard + +#keyboard { background-color: $bg_color; } + +.keyboard { + &-layout { + padding: $base_padding; + spacing: $base_padding; + } + + &-row { spacing: $base_padding; } + + &-key { + @extend %button; + + min-height: 30px; + min-width: 30px; + font-size: 1.2em; + font-weight: bold; + + &:grayed { @include button(insensitive); } + } + + &-subkeys { + padding: $base_padding; + -arrow-border-radius: $borders_color; + -arrow-base: 20px; + -arrow-rise: 10px; + -boxpointer-gap: 0; + } +} diff --git a/data/theme/cinnamon-sass/widgets/_menus.scss b/data/theme/cinnamon-sass/widgets/_menus.scss new file mode 100644 index 0000000000..905e34a1f3 --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_menus.scss @@ -0,0 +1,140 @@ +$menuitem_border_radius: $base_border_radius * 1; + +//container of the popup menu +.menu { + min-width: 15em; + color: $fg_color; + margin: 6px; +} + +// popup content +.popup-menu-content { + padding: $base_padding; + background-color: $bg_color; + border-radius: $base_border_radius * 2; + border: 1px solid $borders_color; + box-shadow: 0 0 6px $shadow_color; +} + +// menu items +.popup-menu-item { + @extend %menuitem; + + &:active { + background-color: $light_bg_color; + } + + &:insensitive { + color: $insensitive_fg_color; + background: none; + } +} + +// Used in the battery applet for the status +// .popup-inactive-menu-item { +// color: $fg_color; + +// &:insensitive { color: $insensitive_fg_color; } +// } + +.popup-slider-menu-item { + @extend %slider; +} + +// icons in menus +.popup-menu-arrow, +.popup-menu-icon { + icon-size: $scalable_icon_size; +} + +// popup submenus +.popup-sub-menu { + border-radius: $base_border_radius + 1; + margin: 0 $base_margin; + margin-bottom: $base_padding; + border: 1px solid transparentize(black, 0.9); + + .popup-menu-item { + border-radius: 0; + @extend %menuitem; + background-color: $base_color; + margin: 0; + + &:active { background-color: $light_base_color; } + + &:first-child { + border-radius: $base_border_radius $base_border_radius 0 0; + } + + &:last-child { + border-radius: 0 0 $base_border_radius $base_border_radius; + } + + &:only-child, + &:first-child:last-child { + border-radius: $base_border_radius; + } + } + + StScrollBar { + padding: 4px; + StBin#trough, StBin#vhandle { border-width: 0; } + } +} + +// This is the first submenu item that contains the arrow +.popup-submenu-menu-item { + &:open {} + &:active {} +} + +// separator +.popup-separator-menu-item { + -gradient-height: 1px; + -gradient-start: $borders_color; + -gradient-end: $borders_color; + -margin-horizontal: 0; + height: 1px; +} + +// scale view context menu - just duplicating regular popupmenu here +.popup-combo-menu { + padding: $base_padding; + background-color: $bg_color; + border-radius: $base_border_radius * 1.25; + border: 1px solid $borders_color; + box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.2); +} + +// Used by the recents applet +.popup-combobox-item { + @extend %menuitem; + + padding: 0 $base_padding * 2; +} + +// this is not currently being used anywhere +.popup-alternating-menu-item:alternate { font-weight: normal; } + +// Used in the power applet for display of battery items +.popup-device-menu-item { + spacing: .5em; + + @extend %heading; + color: $fg_color; + + &:insensitive { color: $fg_color; } + + .popup-inactive-menu-item { + font-weight: normal; + color: $fg_color; + } +} + +// Used in window quick list and power applet +.popup-subtitle-menu-item { font-weight: normal; } + +// Used to set the color of the signal strength icons in network applet +.nm-menu-item-icons { spacing: .5em; } + +.wireless-active:insensitive { color: red; } diff --git a/data/theme/cinnamon-sass/widgets/_notifications.scss b/data/theme/cinnamon-sass/widgets/_notifications.scss new file mode 100644 index 0000000000..ae3bd08bec --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_notifications.scss @@ -0,0 +1,48 @@ +$notification_width: 34em; + +#notification { + width: $notification_width; + border-radius: $base_border_radius; + border: 1px solid $borders_color; + box-shadow: 0 2px 4px 2px $shadow_color; + background-color: $bg_color; + padding: $base_padding * 2; + margin-from-right-edge-of-screen: 20px; + spacing-rows: 10px; + spacing-columns: 10px; + + &.multi-line-notification { + padding-bottom: $base_padding * 2; + color: $fg_color; + } + + &-body { spacing: $base_padding; } + &-actions { spacing: $base_padding * 2; } + + &-scrollview {} + + StEntry {} +} + +.notification { + + /* We use row-span = 2 for the image cell, which prevents its height preferences to be + taken into account during allocation, so its height ends up being limited by the height + of the content in the other rows. To avoid showing a stretched image, we set the minimum + height of the table to be ICON_SIZE + IMAGE_SIZE + spacing-rows = 24 + 125 + 10 = 159 */ + &-with-image { min-height: 159px; } + + &-button { + @extend %button; + + padding: $base_padding $base_padding * 2; + } + + &-icon-button { + @extend %button; + + padding: $base_padding; + } + + &-icon-button > StIcon {} +} \ No newline at end of file diff --git a/data/theme/cinnamon-sass/widgets/_osd.scss b/data/theme/cinnamon-sass/widgets/_osd.scss new file mode 100644 index 0000000000..d8e62832a0 --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_osd.scss @@ -0,0 +1,95 @@ +// various on screen popups + +$barlevel_height: 6px; + +$ws_indicator_height: 32px; +$ws_dot_active: $ws_indicator_height / 3; +$ws_dot_inactive: $ws_indicator_height / 6; + +// media keys osd + +.media-keys-osd { + @extend %osd_base; + @extend %title_4; + + margin-bottom: 4em; + border-radius: 9999px; + font-weight: bold; + spacing: $base_padding * 2; + padding: $base_padding * 2 $base_padding * 4; + & > * { spacing: $base_padding * 2; } + + StIcon { + icon-size: 32px; + } + + StLabel { + &:ltr { margin-right: $base_padding; } + &:rtl { margin-left: $base_padding; } + } + + .level { + min-width: 160px; + -barlevel-height: $barlevel_height; + -barlevel-background-color: $base_color; + -barlevel-active-background-color: $fg_color; + -barlevel-amplify-color: $warning_color; + -barlevel-amplify-separator-width: $base_padding * 0.5; + + &:ltr { margin-right: $base_padding; } + &:rtl { margin-left: $base_padding; } + } + + .level-bar { + border-radius: $base_border_radius; + background-color: $fg_color; + } +} + +.info-osd { + @extend %osd_base; + + font-size: 1.2em; + font-weight: 700; + text-align: center; +} + +.workspace-switch-osd { + @extend %osd_base; + @extend %title_4; + + margin-bottom: 4em; + border-radius: 9999px; + font-weight: bold; + padding: $base_padding * 2 $base_padding * 6 0 $base_padding * 6; + + &-indicator-box { spacing: $base_padding * 2; } + + &-indicator { + background-color: transparentize($fg_color, 0.5); + padding: $ws_dot_inactive / 2; + margin: ($ws_indicator_height - $ws_dot_inactive) / 2; + border-radius: $ws_indicator_height; + + &:active { + background-color: $accent_bg_color; + padding: $ws_dot_active / 2; + margin: ($ws_indicator_height - $ws_dot_active) / 2; + } + } +} + +.monitor-label { + border-radius: 0; + color: black; + padding: $base_padding * 2; + text-align: center; +} + +// resize popup + +.resize-popup { + @extend %osd_base; + + padding: $base_padding; +} \ No newline at end of file diff --git a/data/theme/cinnamon-sass/widgets/_panel.scss b/data/theme/cinnamon-sass/widgets/_panel.scss new file mode 100644 index 0000000000..0d8a9b25cb --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_panel.scss @@ -0,0 +1,86 @@ + + +.panel { + + &-top, &-bottom, &-left, &-right{ + font-weight: bold; + color: $fg_color; + background-color: $panel_bg; + } + + &Left { + spacing: 4px; + + &:dnd { background-color: rgba(255,0,0,0.2); } // For panel edit mode + &:ltr { padding-right: 4px; } + &:rtl { padding-left: 4px; } + + &.vertical { + padding: 0; + &:ltr { padding-right: 0px; } + &:rtl { padding-left: 0px; } + } + } + + &Right { + + &:dnd { background-color: rgba(0,0,255,0.2); } + + &:ltr { + padding-left: 4px; + spacing: 0; + } + &:rtl { + padding-right: 4px; + spacing: 0; + } + + &.vertical { + padding: 0; + + &:ltr { + padding-left: 0; + spacing: 0; + } + &:rtl { + padding-right: 0; + spacing: 0; + } + } + } + + &Center { + spacing: 4px; + + &:dnd { background-color: rgba(0,255,0,0.2); } + + &.vertical { + padding-left: 0; + padding-right: 0; + } + } + + // create a border on the side we want for each location + &-top { box-shadow: inset 0 -1px $borders_color; } + &-bottom { box-shadow: inset 0 1px $borders_color; } + &-left { box-shadow: inset -1px 0 $borders_color; } + &-right { box-shadow: inset 1px 0 $borders_color; } + + // used when adding a new panel + &-dummy { + background-color: transparentize($error_color, 0.5); + + &:entered { background-color: transparentize($error_color, 0.4); } + } + + &-status-button {} // used by the keyboard applet but see no reason for it +} + +// these are available but we aren't using them here +.panel-corner {} +.panel-corner:overview {} +.panel-corner:active {} +.panel-corner:focus {} + +// this is needed to highlight a specific panel when using the panel settings +#panel:highlight { background-color: mix($panel_bg, $error_bg_color, 75%); } diff --git a/data/theme/cinnamon-sass/widgets/_startmenu.scss b/data/theme/cinnamon-sass/widgets/_startmenu.scss new file mode 100644 index 0000000000..c2e3cc5a44 --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_startmenu.scss @@ -0,0 +1,96 @@ +$menu_outer_padding: 9px; +$menu_outer_border_radius: $base_border_radius * 1.25; + +%start_menu_button { + padding: $base_padding; + spacing: $base_margin; + border-radius: $base_border_radius; +} + +.menu { + + // this can be used to color the entire menu background but we aren't using it here + &-background {} + + &-favorites-box { + padding: $base_padding * 1.5; + background-color: $light_bg_color; + border: 1px solid transparentize(black, 0.9); + border-radius: $base_border_radius; + } + + &-favorites-button { + padding: $base_padding * 1.5; + border-radius: $base_border_radius; + + &:hover { background-color: $lightest_bg_color; } + } + + &-categories-box { padding: $menu_outer_padding $base_padding * 4; } + &-applications-box { padding: $menu_outer_padding; } + &-applications-inner-box { + &:ltr { padding-left: $base_padding * 4; } + &:rtl { padding-right: $base_padding * 4; } + } + + &-application-button { + @extend %start_menu_button; + + &-label { padding: 0; } + + &:highlighted { font-weight: bold; } + + &-selected { + @extend %start_menu_button; + + background-color: $light_bg_color; + + &:highlighted { font-weight: bold; } + } + } + + &-category-button { + @extend %start_menu_button; + + &-label { padding: 0; } + + &:hover { background-color: $lighter_bg_color; } + + &-selected { + @extend %start_menu_button; + + background-color: $light_bg_color; + } + + &-greyed { + @extend %start_menu_button; + color: $insensitive_fg_color; + font-style: italic; + + StIcon { opacity: 0.5; } + } + } + + &-context-menu {} + + &-selected-app-box { + padding-right: $base_padding * 4; + padding-left: $base_padding * 4; + text-align: right; + } + + &-selected-app-title { @extend %heading; } + &-selected-app-description { color: $insensitive_fg_color; } + + &-search-box { + padding: 0 0 $base_padding $menu_outer_padding; + } +} + +#menu-search-entry { + @extend %entry; +} + +.menu-search-entry-icon { + icon-size: $scalable_icon_size; +} diff --git a/data/theme/cinnamon-sass/widgets/_switch-check.scss b/data/theme/cinnamon-sass/widgets/_switch-check.scss new file mode 100644 index 0000000000..a7d7b334fa --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_switch-check.scss @@ -0,0 +1,47 @@ +// these are equal to the size of the svg +$switch_height: 26px; +$switch_width: 46px; + +$check_height: 20px; +$check_width: 20px; + +// switch + +.toggle-switch { + height: $switch_height; + width: $switch_width; + background-size: contain; + background-image: url("toggle-off.svg"); + + &:checked { background-image: url("toggle-on.svg"); } +} + +// check + +.check-box { + CinnamonGenericContainer { spacing: 0.8em; } + + StBin { + width: $check_width; + height: $check_height; + background-image: url("checkbox-off.svg"); + } + &:focus StBin { background-image: url("checkbox-off.svg"); } + &:checked StBin { background-image: url("checkbox.svg"); } + &:focus:checked StBin { background-image: url("checkbox.svg"); } +} + +// radio + +.radiobutton { + CinnamonGenericContainer { spacing: 0.8em; } + + StBin { + width: $check_width; + height: $check_height; + background-image: url("radio-off.svg"); + } + &:focus StBin { background-image: url("radio-off.svg"); } + &:checked StBin { background-image: url("radio.svg"); } + &:focus:checked StBin { background-image: url("radio.svg"); } +} diff --git a/data/theme/cinnamon-sass/widgets/_windowlist.scss b/data/theme/cinnamon-sass/widgets/_windowlist.scss new file mode 100644 index 0000000000..4c8028e0d2 --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_windowlist.scss @@ -0,0 +1,160 @@ + +// grouped window list + +.grouped-window-list { + &-box {} + + &-item-label { + width: 15em; + min-width: 5px; + } + + &-item-box { + padding: 0 $base_padding; + + &.top, + &.bottom { + border-bottom-width: 2px; + } + + &.right { + padding-left: 0; + padding-right: 0; + border-right-width: 2px; + + & StBin { padding-right: 0; } + } + + &.left { + padding-left: 0; + padding-right: 0; + border-left-width: 2px; + + & StBin { padding-left: 1px; } + } + + &:hover { background-color: $lighter_bg_color; } + &:focus { background-color: $lightest_bg_color; } + &:active { border-color: $accent_bg_color; } + + & .progress { background-color: transparentize($success_color, 0.2); } + } + + &-item-demands-attention { background-color: $destructive_color; } + + &-thumbnail-label { padding-left: 4px; } + &-thumbnail-alert { background: transparentize($destructive_color, 0.7); } + + &-thumbnail-menu { + border: 1px solid $borders_color; + background-color: $bg_color; + border-radius: $base_border_radius; + box-shadow: 0 0 6px 0 $shadow_color; + + > StBoxLayout { padding: 4px; } + + .item-box { + padding: 10px; + spacing: 4px; + + &:outlined { + border: 2px solid transparentize($fg_color, 0.5); + } + + &:selected { background-color: $light_bg_color; } + } + + .thumbnail { width: 256px; } + .separator { + width: 1px; + background-color: $borders_color; + } + } + + &-button-label { padding-left: 4px;} + + &-number-label { + font-size: 0.8em; + z-index: 99; + } + + &-badge { + border-radius: 9999px; + background-color: $bg_color; + } +} + +// classic window list + +.window-list { + &-box { + spacing: $base_padding; + padding-left: $base_padding; + padding-top: 1px; + + &.vertical { + spacing: $base_margin; + padding: $base_padding 0; + } + + &:highlight { background-color: transparentize($error_color, 0.5); } + } + + &-item-label {} + + &-item-box { + padding: 0 $base_padding; + color: transparentize($fg_color, 0.2); + + &.top, + &.bottom { + border-bottom-width: 2px; + + StLabel { padding-left: 2px; } + } + + &.right { + padding-left: 0; + padding-right: 0; + border-right-width: 2px; + + StBin { + padding-right: 0; + padding-left: 5px; + } + } + + &.left { + padding-left: 0; + padding-right: 0; + border-left-width: 2px; + + StBin { + padding-left: 0; + padding-right: 5px; + } + } + + &:hover { + background-color: $light_bg_color; + } + + &:focus { + border-color: $accent_bg_color; + background-color: $lightest_bg_color; + } + + & .progress { background-color: transparentize($success_color, 0.2); } + } + + &-item-demands-attention { background-color: $destructive_color; } + + &-preview { + border: 1px solid $borders_color; + background-color: $bg_color; + border-radius: $base_border_radius; + padding: $base_padding * 2; + spacing: $base_margin; + box-shadow: 0 0 6px 0 $shadow_color; + } +} diff --git a/data/theme/cinnamon.css b/data/theme/cinnamon.css deleted file mode 100644 index fee82a426e..0000000000 --- a/data/theme/cinnamon.css +++ /dev/null @@ -1,2191 +0,0 @@ -/* ################################################################### - * Section common with Gnome Shell - * ... contains a few cinnamon specific styles (rare occurrences) - * ###################################################################*/ -stage { -} -.cinnamon-link { - color: #0000ff; - text-decoration: underline; -} -.cinnamon-link:hover { - color: #0000e0; -} -.label-shadow { - color: rgba(0,0,0,0.5); -} -StScrollBar { - padding: 0px; -} -StScrollView.vfade { - -st-vfade-offset: 68px; -} -StScrollView StScrollBar { - min-width: 16px; - min-height: 16px; - padding: 2px; -} - -StScrollBar StBin#trough { - background-color: rgba(0,0,0,0); - border: 1px solid #555555; - border-radius: 4px; -} -StScrollBar StButton#vhandle { - background-image: url("scroll-vhandle.svg"); - background-color: rgba(204,204,204,0.3); - border: 1px solid #555555; - border-radius: 4px; -} -StScrollBar StButton#hhandle { - background-image: url("scroll-hhandle.svg"); - background-color: rgba(204,204,204,0.3); - border: 1px solid #555555; - border-radius: 4px; -} -StScrollBar StButton#hhandle:hover, -StScrollBar StButton#vhandle:hover { - background-color: rgba(204,204,204,0.5); -} -.separator { - -gradient-height: 2px; - -gradient-start: rgba(85,85,85,1); - -gradient-end: #555555; - -margin-horizontal: 1.5em; - height: 1em; -} -.slider { - height: 1em; - min-width: 15em; - -slider-height: 0.3em; - -slider-background-color: #666666; - -slider-border-color: #555555; - -slider-active-background-color: #CCCCCC; - -slider-active-border-color: #DDDDDD; - -slider-border-width: 1px; - -slider-handle-radius: 0.5em; -} -#Tooltip { - border: 1px solid rgba(212,185,67,1.0); - border-radius: 4px; - padding: 2px 12px; - background-gradient-end: rgba(251,234,159,0.9); - background-gradient-start: rgba(254,245,198,0.9); - background-gradient-direction: vertical; - color: #000000; - font-weight: normal; - text-align: center; -} -.ripple-pointer-location { - width: 50px; - height: 50px; - border-radius: 25px; - background-color: rgba(160,160,160,0.3); - box-shadow: 0 0 2px 2px rgba(160,160,160,1.0); -} -/* =================================================================== - * Shared button properties - * ===================================================================*/ -.notification-button, .notification-icon-button, -.modal-dialog-button, -.sound-player-overlay StButton { - color: white; - border: 1px solid #8b8b8b; - background-gradient-direction: vertical; - background-gradient-start: rgba(255, 255, 255, 0.2); - background-gradient-end: rgba(255, 255, 255, 0); -} -.notification-button:hover, -.notification-icon-button:hover, .modal-dialog-button:hover, -.sound-player-overlay StButton:hover { - background-gradient-start: rgba(255, 255, 255, 0.3); - background-gradient-end: rgba(255, 255, 255, 0.1); -} -.notification-button:focus, -.notification-icon-button:focus, -.modal-dialog-button:focus, -.sound-player-overlay StButton:focus { - border: 2px solid #8b8b8b; -} -.notification-button:active, .notification-icon-button:active, -.modal-dialog-button:active, .modal-dialog-button:pressed, -.sound-player-overlay StButton:active { - background-gradient-start: rgba(255, 255, 255, 0); - background-gradient-end: rgba(255, 255, 255, 0.2); -} -/* =================================================================== - * PopupMenu (popupMenu.js) - * ===================================================================*/ - /* .popup-menu-boxpointer and .popup-menu are kept for compatibility - with cinnamon version under 3.2. Use .menu in version 3.2 and above */ -.popup-menu-boxpointer { - -arrow-border-radius: 8px; - -arrow-background-color: rgba(80,80,80,0.9); - -arrow-border-width: 2px; - -arrow-border-color: #a5a5a5; - -arrow-base: 24px; - -arrow-rise: 11px; -} -.popup-menu { - color: #ffffff; - min-width: 100px; -} -.menu { - border-radius: 8px; - background-color: rgba(80,80,80,0.9); - border-width: 2px; - border-color: #a5a5a5; - color: #ffffff; - min-width: 100px; -} -.popup-menu-arrow { - icon-size: 1.14em; -} -.popup-submenu-menu-item:open { - background-color: #4c4c4c; -} -.popup-sub-menu { - background-gradient-start: rgba(80,80,80,0.3); - background-gradient-end: rgba(80,80,80,0.7); - background-gradient-direction: vertical; -} -.popup-sub-menu .popup-menu-item:ltr { - padding-right: 1.75em; -} -.popup-sub-menu .popup-menu-item:rtl { - padding-left: 1.75em; -} -.popup-sub-menu StScrollBar { - padding: 4px; -} -.popup-sub-menu StScrollBar StBin#trough { - border-width: 0px; -} -.popup-sub-menu StScrollBar StBin#vhandle { - background-color: #4c4c4c; - border-width: 0px; -} -.popup-combo-menu { - background-color: rgba(0,0,0,0.9); - padding: 1em 0em; - color: #ffffff; - border: 1px solid #5f5f5f; - border-radius: 9px; -} -/* The remaining popup-menu sizing is all done in ems, so that if you - * override .popup-menu.font-size, everything else will scale with it. - */ -.popup-menu-content { - padding: 1em 0em; -} -.popup-menu-item { - padding: .4em 1.75em; - spacing: 1em; -} -.popup-menu-item:active { - background-color: #4c4c4c; -} -.popup-menu-item:insensitive { - color: #9f9f9f; -} -.popup-image-menu-item { -} -.popup-combobox-item { - spacing: 1em; -} -.popup-separator-menu-item { - -gradient-height: 2px; - -gradient-start: rgba(85,85,85,1); - -gradient-end: #555555; - -margin-horizontal: 1.5em; - height: 1em; -} -.popup-alternating-menu-item:alternate { - font-weight: bold; -} -.popup-slider-menu-item { - height: 1em; - min-width: 15em; - -slider-height: 0.3em; - -slider-background-color: #666666; - -slider-border-color: #555555; - -slider-active-background-color: #CCCCCC; - -slider-active-border-color: #DDDDDD; - -slider-border-width: 1px; - -slider-handle-radius: 0.5em; -} -.popup-device-menu-item { - spacing: .5em; -} -.popup-inactive-menu-item { - font-weight: normal; - color: #999; -} -.popup-subtitle-menu-item { - font-weight: bold; -} -.popup-menu-icon { - icon-size: 1.14em; -} -/* Switches (to be used in menus) */ -.toggle-switch { - width: 64px; - height: 22px; -} -.toggle-switch-us { - background-image: url("toggle-off-us.svg"); -} -.toggle-switch-us:checked { - background-image: url("toggle-on-us.svg"); -} -.toggle-switch-intl { - background-image: url("toggle-off-intl.svg"); -} -.toggle-switch-intl:checked { - background-image: url("toggle-on-intl.svg"); -} -.nm-menu-item-icons { - spacing: .5em; -} -/* =================================================================== - * Panel (panel.js) - * ===================================================================*/ -#panel { - color: #ffffff; - background-color: #555555; - font-weight: normal; - height: 26px; - width: 32px; -} -#panel:highlight { - background-color: #aa5555; -} -.panel-dummy { - background-color: rgba(50, 50, 50, 0.4); -} -.panel-dummy:entered { - background-color: rgba(255, 35, 35, 0.4); -} -.panelLeft { - spacing: 4px; -} -.panelCenter { - spacing: 4px; -} -.panelRight { - spacing: 4px; -} -.panelLeft:dnd { - background-gradient-direction: vertical; - background-gradient-start: rgba(255,0,0,0.05); - background-gradient-end: rgba(255,0,0,0.2); -} -.panelCenter:dnd { - background-gradient-direction: vertical; - background-gradient-start: rgba(0,255,0,0.05); - background-gradient-end: rgba(0,255,0,0.2); -} -.panelRight:dnd { - background-gradient-direction: vertical; - background-gradient-start: rgba(0,0,255,0.05); - background-gradient-end: rgba(0,0,255,0.2); -} -.panelLeft:ltr { - padding-right: 4px; -} -.panelLeft:rtl { - padding-left: 4px; -} -.panelRight:ltr { - padding-left: 0px; - spacing: 0px; -} -.panelRight:rtl { - padding-right: 0px; - spacing: 0px; -} -.panelLeft.vertical { - padding: 0px; -} -.panelRight.vertical { - padding: 0px; -} -.panelCenter.vertical { - padding-left: 0px; - padding-right: 0px; -} -.panelLeft.vertical:dnd { -} -.panelCenter.vertical:dnd { -} -.panelRight.vertical:dnd { -} -.panel-top { -} -.panel-bottom { -} -.panel-left { -} -.panel-right { -} -.panel-status-button { - border: 0px solid #8b8b8b; - -natural-hpadding: 3px; - -minimum-hpadding: 3px; - font-weight: bold; - color: #ccc; - height: 22px; -} -.panel-status-button:hover { - color: white; -} -.system-status-icon { - padding-left: 0px; - padding-right: 0px; - spacing: 0px; - margin: 0px; -} - -.panel-corner { - -panel-corner-radius: 0px; - -panel-corner-background-color: black; - -panel-corner-inner-border-width: 2px; - -panel-corner-inner-border-color: transparent; - -panel-corner-outer-border-width: 1px; - -panel-corner-outer-border-color: #536272; -} -.panel-corner:active, -.panel-corner:overview, -.panel-corner:focus { - -panel-corner-inner-border-color: rgba(255,255,255,0.8); -} - -.panel-button #appMenuIcon { - app-icon-bottom-clip: 1px; -} -.panel-button:active #appMenuIcon, -.panel-button:checked #appMenuIcon, -.panel-button:focus #appMenuIcon { - app-icon-bottom-clip: 2px; -} -.panel-button { - -natural-hpadding: 6px; - -minimum-hpadding: 2px; - font-weight: bold; - color: #ccc; - transition-duration: 100; -} -.panel-button:hover { - color: white; - text-shadow: black 0px 2px 2px; -} -.panel-button:active, -.panel-button:overview, -.panel-button:focus { - -} -.panel-button:active > .system-status-icon, -.panel-button:checked > .system-status-icon, -.panel-button:focus > .system-status-icon { - icon-shadow: black 0px 2px 2px; -} -.panel-menu { - -boxpointer-gap: 4px; -} -.popup-menu-item-dot { -} -.system-status-icon { - icon-size: 1.14em; -} -/* =================================================================== - * Overview - * ===================================================================*/ -#overview { - spacing: 12px; -} - -.workspace-controls { - visible-height: 32px; /* Amount visible before hovering */ -} -.workspace-thumbnails-background { - border: 1px solid rgba(128, 128, 128, 0.4); - border-right: 0px; - border-radius: 9px 9px 0px 0px; - background-color: rgba(0, 0, 0, 0.5); - padding: 8px; -} -.workspace-thumbnails-background:rtl { - border-right: 1px; - border-left: 0px; - border-radius: 9px 9px 0px 0px; -} -.workspace-thumbnails { - spacing: 14px; -} -.workspace-add-button { - background-image: url("add-workspace.png"); - height: 200px; - width: 35px; - transition-duration: 300; -} -.workspace-add-button:hover { - background-image: url("add-workspace-hover.png"); - transition-duration: 300; -} - -.workspace-close-button { - background-image: url("close-window.svg"); - height: 34px; - width: 34px; - -cinnamon-close-overlap: 20px; -} - -.workspace-thumbnail-indicator { - outline: 2px solid white; - border: 1px solid #888; -} - -.window-caption { - background: rgba(85,85,85,0.8); - border: 2px solid #a5a5a5; - border-radius: 4px; - padding: .5em; - spacing: .5em; - -cinnamon-caption-spacing: 8px; - color: #ccc; - max-width: 20em; -} -.window-caption:focus { - color: #fff; -} - -.window-border { - border: 3px #a5a5a5; - border-radius: 4px; - background-color: rgba(255,255,255,.05); - /* Cover rounded corners and some bad adjustment gaps */ - box-shadow: 0 0 0 1px #a5a5a5 inset; -} - -.window-close { - background-image: url("close-window.svg"); - height: 28px; - width: 28px; - -cinnamon-close-overlap: 13px; -} -.window-close:hover { - background-image: url("close-window-hover.svg"); -} - -.window-close-area { - background-image: url("trash-icon.png"); - background-size: 100px; - background-color: rgba(60, 60, 60, 0.8); - border: 4px solid rgba(128,128,128,0.8); - border-bottom-width: 0px; - border-radius: 20px 20px 0px 0px; - height: 120px; - width: 400px; -} - -.overview-icon { - border-radius: 4px; - padding: 3px; - border: 1px rgba(0,0,0,0); - color: white; - transition-duration: 100; - text-align: center; -} - -.overview-empty-placeholder { - color: #ffffff; - font-size: 2em; -} - -.expo-background { - background-gradient-start: #000; - background-gradient-end: #AAA; - background-gradient-direction: vertical; -} - -.workspace-overview-background-shade { - background-color: rgba(0,0,0,0.4); -} - -.expo-workspace-thumbnail-frame { - border: 1px, rgba(64,64,64,0.9); - background-color: rgba(64,64,64,0.9); -} - -.expo-workspace-thumbnail-frame#active { - border: 2px, rgba(32,32,32,0.9); - background-color: rgba(32,32,32,0.9); -} - -/* =================================================================== - * Looking Glass - * ===================================================================*/ -#LookingGlassDialog { - background-color: rgba(85,85,85,0.85); - spacing: 4px; - padding: 4px; - border: 2px solid grey; - border-radius: 4px; - color: #CCCCCC; -} -/* =================================================================== - * Date applet - * ===================================================================*/ -/*calendar-background allows the date applet calendar to be themed separately from other applet menus*/ -.calendar-background { -} - -.calendar-main-box { - margin: 0 .8em 0 .8em; -} - -.calendar { - /*padding: 0 0.5em 0.4em;*/ - spacing-rows: 0px; - spacing-columns: 0px; -} - -.calendar-events-main-box { - height: 300px; - margin-right: 0.8em; - padding: .5em; - min-width: 350px; - border: 1px solid #666; - border-radius: 8px; - background-gradient-direction: vertical; - background-gradient-start: rgba(85,85,85,0.8); - background-gradient-end: rgba(85,85,85,0.2); -} - -.calendar-events-no-events-box { -} - -.calendar-events-no-events-button { - margin: 6px 0 6px 0; - padding: 6px; - border-radius: 4px; -} - -.calendar-events-no-events-button:hover { - background-gradient-direction: vertical; - background-gradient-start: rgba(255,255,255,0.2); - background-gradient-end: rgba(255,255,255,0.08); - box-shadow: inset 0px 0px 1px 1px rgba(255,255,255,0.06); -} - -.calendar-events-no-events-icon { - color: #cccccc; -} - -.calendar-events-no-events-label { - font-size: 1.1em; - color: #cccccc; - font-weight: bold; - text-align: center; - margin-top: 10px; -} - -.calendar-events-date-label { - padding: .2em 0 .75em .2em; - font-size: 1.1em; - color: #cccccc; - font-weight: bold; - text-align: center; -} - -.calendar-events-event-container { - padding: .1em; -} - -.calendar-events-scrollbox { - -} - -.calendar-events-main-box .separator { - -margin-horizontal: 1em; - -gradient-height: 1px; - -gradient-start: #666666; - -gradient-end: #666666; -} - -.calendar-event-button { - margin: 6px 0 6px 0; - border-radius: 4px; -} - -.calendar-event-button:hover { - background-gradient-direction: vertical; - background-gradient-start: rgba(255,255,255,0.2); - background-gradient-end: rgba(255,255,255,0.08); - box-shadow: inset 0px 0px 1px 1px rgba(255,255,255,0.06); -} - -.calendar-event-color-strip { - width: 4px; - border-radius: 4px 0 0 4px; -} - -.calendar-event-row-content { - margin: 7px; -} - -.calendar-event-time-past { - color: rgba(204,204,204,.3); - font-weight: bold; - text-align: left; - margin-bottom: .6em; -} - -.calendar-event-time-present { - font-weight: bold; - text-align: left; - margin-bottom: .6em; -} - -.calendar-event-time-present:all-day { - color: rgba(0,255,0,0.6); -} - -.calendar-event-time-future { - text-align: left; - margin-bottom: .6em; -} - -.calendar-event-countdown { - color: #cccccc; - font-weight: bold; - text-align: right; - margin-bottom: .6em; -} - -.calendar-event-countdown:soon { - color: #ffffff; -} - -.calendar-event-countdown:imminent { - color: rgba(255,255,0,0.6); -} - -.calendar-event-countdown:current { - color: rgba(0,255,0,0.6); -} - -.calendar-event-summary { - color: #cccccc; - text-align: left; - width: 200px; -} - -.calendar-today-home-button, -.calendar-today-home-button-enabled { - margin: 6px 0 6px 0; - padding: 6px; - border-radius: 4px; -} - -.calendar-today-home-button-enabled:hover { - background-gradient-direction: vertical; - background-gradient-start: rgba(255,255,255,0.2); - background-gradient-end: rgba(255,255,255,0.08); - box-shadow: inset 0px 0px 1px 1px rgba(255,255,255,0.06); -} - -.calendar-today-day-label { - font-size: 1.75em; - color: #cccccc; - font-weight: bold; - text-align: center; - padding-bottom: .1em; -} - -.calendar-today-date-label { - font-size: 1.1em; - color: #cccccc; - font-weight: bold; - text-align: center; -} - -.calendar-month-label { - color: #cccccc; - padding-bottom: 8px; - padding-top: 8px; - font-weight: bold; -} -.calendar-change-month-back { - width: 18px; - height: 12px; - background-image: url("calendar-arrow-left.svg"); - border-radius: 4px; -} -.calendar-change-month-back:rtl { - background-image: url("calendar-arrow-right.svg"); -} -.calendar-change-month-back:hover { - background-color: #999999; -} -.calendar-change-month-back:active { - background-color: #aaaaaa; -} -.calendar-change-month-forward { - width: 18px; - height: 12px; - background-image: url("calendar-arrow-right.svg"); - border-radius: 4px; -} -.calendar-change-month-forward:rtl { - background-image: url("calendar-arrow-left.svg"); -} -.calendar-change-month-forward:hover { - background-color: #999999; -} -.calendar-change-month-forward:active { - background-color: #aaaaaa; -} - -.calendar-day-event-dot-box { - margin-top: 1.75em; - - /* any other way do do something like this? */ - max-rows: 1; -} - -.calendar-day-event-dot { - margin: 1px; - border-radius: 2px; - width: 4px; - height: 4px; -} - -.calendar-day-base { - text-align: center; - width: 2.4em; - height: 2.4em; -} -.calendar-day-base:hover { - color: #fff; - font-weight: bold; -} -.calendar-day-base:active { - background-color: #444444; -} - -.calendar-day-heading { - color: #cccccc; - padding-top: 1em; -} -.calendar-week-number { - color: #cccccc; - font-weight: bold; -} -/* Hack used in lieu of border-collapse - see calendar.js */ -.calendar-day:ltr { - border: 1px solid #333333; - border-top-width: 0; - border-left-width: 0; -} -.calendar-day-top:ltr { - border-top-width: 1px; -} -.calendar-day-left:ltr { - border-left-width: 1px; -} -.calendar-day:rtl { - border: 1px solid #333333; - border-top-width: 0; - border-right-width: 0; -} -.calendar-day-top:rtl { - border-top-width: 1px; -} -.calendar-day-left:rtl { - border-right-width: 1px; -} -.calendar-work-day { -} -.calendar-nonwork-day { - background-color: rgba(128, 128, 128, 0.1); -} -.calendar-today { - background-gradient-direction: vertical; - background-gradient-start: rgba(255,255,255,0.35); - background-gradient-end: rgba(255,255,255,0.15); - color: #cccccc; - font-weight: bold; -} - -.calendar-today:selected { - color: #fff; -} - -.calendar-other-month-day { - color: #888888; - background-color: rgba(64, 64, 64, 0.5); -} - -.calendar-not-today { - color: #cccccc; -} - -.calendar-not-today:selected { - color: #fff; - font-weight: bold; -} - - -/* =================================================================== - * Notifications - * ===================================================================*/ -#notification { - border-radius: 8px 8px 8px 8px; - border: 2px solid #a5a5a5; - background-gradient-direction: vertical; - background-gradient-start: rgba(85,85,85,0.8); - background-gradient-end: rgba(85,85,85,0.8); - padding: 8px 8px 8px 8px; - spacing-rows: 10px; - spacing-columns: 10px; - margin-from-right-edge-of-screen: 20px; - width: 34em; - color: white; -} -#notification.multi-line-notification { - padding-bottom: 8px; - color: white; -} -/* We use row-span = 2 for the image cell, which prevents its height preferences to be - taken into account during allocation, so its height ends up being limited by the height - of the content in the other rows. To avoid showing a stretched image, we set the minimum - height of the table to be ICON_SIZE + IMAGE_SIZE + spacing-rows = 24 + 125 + 10 = 159 */ -.notification-with-image { - min-height: 159px; - color: white; -} -#notification-scrollview { - max-height: 10em; -} -#notification-scrollview > .top-shadow, #notification-scrollview > .bottom-shadow { - height: 1em; -} -#notification-scrollview:ltr > StScrollBar { - padding-left: 6px; -} -#notification-scrollview:rtl > StScrollBar { - padding-right: 6px; -} -#notification-body { - spacing: 5px; -} -#notification-actions { - spacing: 10px; -} -.notification-button { - border-radius: 5px; - padding: 4px 8px 5px; -} -.notification-button:focus { - padding: 3px 8px 4px; -} -.notification-icon-button { - border-radius: 5px; - padding: 5px; -} -.notification-icon-button:focus { - padding: 4px; -} -.notification-icon-button > StIcon { - icon-size: 36px; -} -#notification StEntry { - padding: 4px; - border-radius: 4px; - color: #a8a8a8; - selected-color: black; - border: 1px solid rgba(245,245,245,0.2); - background-gradient-direction: vertical; - background-gradient-start: rgb(200,200,200); - background-gradient-end: white; - transition-duration: 300; - box-shadow: inset 0px 2px 4px rgba(0,0,0,0.6); - caret-color: #a8a8a8; - caret-size: 1px; -} -#notification StEntry:focus { - border: 1px solid #8b8b8b; - color: #333333; - background-gradient-direction: vertical; - background-gradient-start: rgb(200,200,200); - background-gradient-end: white; - caret-color: #545454; - selection-background-color: #808080; -} -/* =================================================================== - * Alt Tab - * ===================================================================*/ -#altTabPopup { - padding: 8px; - spacing: 16px; -} -.switcher-list { - background: rgba(80,80,80,0.8); - border: 2px solid #a5a5a5; - border-radius: 8px; - padding: 20px; - color: white; - text-shadow: black 0px 0px 2px; -} -.switcher-list-item-container { - spacing: 8px; -} -.thumbnail-scroll-gradient-left { - background-gradient-direction: horizontal; - background-gradient-start: rgba(51, 51, 51, 1.0); - background-gradient-end: rgba(51, 51, 51, 0); - border-radius: 24px; - border-radius-topright: 0px; - border-radius-bottomright: 0px; - width: 60px; -} -.thumbnail-scroll-gradient-right { - background-gradient-direction: horizontal; - background-gradient-start: rgba(51, 51, 51, 0); - background-gradient-end: rgba(51, 51, 51, 1.0); - border-radius: 24px; - border-radius-topleft: 0px; - border-radius-bottomleft: 0px; - width: 60px; -} -.switcher-list .item-box { - padding: 8px; - border-radius: 8px; -} -.switcher-list .item-box:outlined { - padding: 6px; - border: 2px solid rgba(85,85,85,1.0); -} -.switcher-list .item-box:selected { - background: rgba(255,255,255,0.33); -} -.switcher-list .thumbnail-box { - padding: 2px; - spacing: 4px; -} -.switcher-list .thumbnail { - width: 256px; -} -.switcher-list .separator { - width: 1px; - background: rgba(255,255,255,0.33); -} -.ripple-box { - width: 104px; - height: 104px; - background-image: url("corner-ripple.png"); -} -.ripple-box:rtl { - background-image: url("corner-ripple.png"); -} -.switcher-arrow { - border-color: rgba(0,0,0,0); - color: #808080; -} -.switcher-arrow:highlighted { - border-color: rgba(0,0,0,0); - color: white; -} -.switcher-preview-backdrop { - background-color: rgba(25,25,25,0.65); -} - -/* =================================================================== - * Modal dialogs - * ===================================================================*/ -.modal-dialog { - border-radius: 24px; - background-color: rgba(85, 85, 85, 0.9); - border: 2px solid #868686; - color: #babdb6; - padding-right: 42px; - padding-left: 42px; - padding-bottom: 30px; - padding-top: 30px; -} -.modal-dialog-button-box { - spacing: 21px; - padding-top: 21px; -} -.modal-dialog-button { - border-radius: 18px; - color: white; - margin-left: 10px; - margin-right: 10px; - padding: 4px 32px 5px; -} -.modal-dialog-button:disabled { - color: rgb(60, 60, 60); -} -.modal-dialog-button:focus { - padding: 3px 31px 4px; -} - -.confirm-dialog-title { - text-align: center; - font-weight: bold; - font-size: 1.5em; - padding-bottom: 12px; -} - -/* Info OSD popup */ -.info-osd { - font-size: 1.2em; - border-radius: 24px; - background-color: rgba(85, 85, 85, 0.9); - border: 2px solid #868686; - color: #babdb6; - padding-right: 20px; - padding-left: 20px; - padding-bottom: 20px; - padding-top: 20px; - text-align: center; -} - -.workspace-osd { - color: #ffffff; - font-weight: bold; - font-size: 3em; -} - -.monitor-label { - border-radius: 0; - color: #000000; - padding: 10px; - text-align: center; -} - -/* =================================================================== - * Run dialog - * ===================================================================*/ -.run-dialog-label { - color: white; - padding-bottom: 15px; - text-align: center; - font-size: 1.5em; - font-weight: bold; -} -.run-dialog-description { - color: white; - padding-top: 15px; - text-align: center; -} -.run-dialog-description.error { - color: #fc4138; -} -.run-dialog-completion-box { - padding-left: 15px; -} -.run-dialog-entry { - font-weight: bold; - width: 23em; - color: white; - selection-background-color: white; - selected-color: black; -} -.run-dialog { - border-radius: 16px; - padding-right: 21px; - padding-left: 21px; - padding-bottom: 0; - padding-top: 15px; -} -.lightbox { - background-color: rgba(0, 0, 0, 0.4); -} - -/* =================================================================== - * Magnifier - * ===================================================================*/ - -.magnifier-zoom-region { - border: 2px solid rgba(128, 0, 0, 1); -} -.magnifier-zoom-region.full-screen { - border-width: 0px; -} -/* =================================================================== - * On screen keyboard - * ===================================================================*/ - -#keyboard { - background-color: #555555; -} -.keyboard-layout { - spacing: 10px; - padding: 10px; -} -.keyboard-row { - spacing: 15px; -} -.keyboard-key { - min-height: 30px; - min-width: 30px; - background-gradient-start: rgba(255,245,245,0.4); - background-gradient-end: rgba(105,105,105,0.1); - background-gradient-direction: vertical; - font-size: 1.2em; - font-weight: bold; - border-radius: 10px; - border: 2px solid #a0a0a0; - color: white; -} -.keyboard-key:grayed { - color: #808080; - border-color: #808080; -} -.keyboard-key:checked, -.keyboard-key:hover { - background: #303030; - border: 3px solid white; -} -.keyboard-key:active { - background: #808080; -} -.keyboard-subkeys { - color: white; - padding: 5px; - -arrow-border-radius: 10px; - -arrow-background-color: #090909; - -arrow-border-width: 2px; - -arrow-border-color: white; - -arrow-base: 20px; - -arrow-rise: 10px; - -boxpointer-gap: 5px; -} - -/* =================================================================== - * Policykit authentication dialog - * ===================================================================*/ -.polkit-dialog { - /* this is the width of the entire modal popup */ - width: 500px; -} -.polkit-dialog-main-layout { - spacing: 10px; -} - -.polkit-dialog-headline { - text-align: center; - font-size: 1.3em; - font-weight: bold; - color: white; -} -.polkit-dialog-description { - text-align: center; - font-size: 1em; - color: white; -} -.polkit-dialog-user-layout { - spacing: 10px; -} -.polkit-dialog-user-layout:rtl { - padding-right: 10px; -} -.polkit-dialog-user-root-label { - color: #ff0000; -} -.polkit-dialog-password-label:ltr { - padding-top: 0.5em; - padding-right: 0.5em; -} -.polkit-dialog-password-label:rtl { - padding-left: 0.5em; -} -.polkit-dialog-password-entry { - padding: 5px; - border-radius: 4px; - color: rgb(64, 64, 64); - border: 2px solid rgba(245,245,245,0.2); - background-gradient-start: rgba(5,5,6,0.1); - background-gradient-end: rgba(254,254,254,0.1); - background-gradient-direction: vertical; - selected-color: black; - caret-color: rgb(64, 64, 64); - caret-size: 1px; - width: 21em; - height: 1.2em; - transition-duration: 300; - box-shadow: inset 0px 2px 4px rgba(0,0,0,0.6); -} -.polkit-dialog-password-entry:focus { - border: 2px solid rgb(136,138,133); - background-gradient-start: rgb(80, 80, 80); - background-gradient-end: white; - background-gradient-direction: vertical; -} -.polkit-dialog-password-entry .capslock-warning { - icon-size: 16px; - warning-color: rgb(64, 64, 64); - padding: 0 4px; -} -.polkit-dialog-error-label { - text-align: center; - font-size: 1em; - color: #ffff00; -} -.polkit-dialog-info-label { - font-size: 1em; -} -/* intentionally left transparent to avoid dialog changing size */ -.polkit-dialog-null-label { - font-size: 10pt; - color: rgba(0,0,0,0); -} - -/* ################################################################### - * Cinnamon Specific Section - * ###################################################################*/ -/* =================================================================== - * Menu (menu.js) - * ===================================================================*/ -/* Main menu title */ -/* menu-background allows the menu applet to be themed separately from other applet menus */ -.menu-background { -} -.menu-favorites-box { - padding: 0.8em; - border: 1px solid #666; - border-radius: 8px; - background-gradient-direction: vertical; - background-gradient-start: rgba(85,85,85,0.8); - background-gradient-end: rgba(85,85,85,0.2); - transition-duration: 300; -} -.menu-favorites-button { - padding: 0.8em; -} -.menu-favorites-button:hover { - color: white; - background-gradient-direction: vertical; - background-gradient-start: rgba(255,255,255,0.2); - background-gradient-end: rgba(255,255,255,0.08); - box-shadow: inset 0px 0px 1px 1px rgba(255,255,255,0.06); - border-radius: 4px; -} - -.menu-categories-box { - padding-top: 10px; - padding-left: 30px; - padding-right: 30px; - padding-bottom: 10px; -} -.menu-applications-inner-box { - margin-top: 10px; - margin-left: 10px; - margin-right: 10px; - margin-bottom: 0px; -} -.menu-applications-outer-box { - padding-top: 10px; - padding-left: 10px; - padding-right: 10px; - padding-bottom: 0px; -} -.menu-application-button { - padding-top: 7px; - padding-left: 7px; - padding-right: 7px; - padding-bottom: 7px; -} -.menu-application-button:highlighted { - /* This style is used in menu application buttons for applications which were newly installed */ - font-weight: bold; -} -.menu-application-button-selected { - padding-top: 7px; - padding-left: 7px; - padding-right: 7px; - padding-bottom: 7px; - color: white; - background-gradient-direction: vertical; - background-gradient-start: rgba(255,255,255,0.2); - background-gradient-end: rgba(255,255,255,0.08); - box-shadow: inset 0px 0px 1px 1px rgba(255,255,255,0.06); - border-radius: 4px; -} -.menu-application-button-selected:highlighted { - /* This style is used in menu application buttons for applications which were newly installed */ - font-weight: bold; -} -.menu-application-button-label:ltr { - padding-left: 5px; -} -.menu-application-button-label:rtl { - padding-right: 5px; -} -.menu-category-button { - padding-top: 7px; - padding-left: 7px; - padding-right: 7px; - padding-bottom: 7px; -} -.menu-category-button:hover { - background-color: rgba(128,128,128,0.2); - border-radius: 4px; - border-image: none; -} -.menu-category-button-greyed { - padding-top: 7px; - padding-left: 7px; - padding-right: 7px; - padding-bottom: 7px; - color: #9C9C9C; - font-style: italic; -} -.menu-category-button-greyed StIcon { - opacity: 0.5; -} -.menu-category-button-selected { - padding-top: 7px; - padding-left: 7px; - padding-right: 7px; - padding-bottom: 7px; - color: white; - background-gradient-direction: vertical; - background-gradient-start: rgba(255,255,255,0.2); - background-gradient-end: rgba(255,255,255,0.08); - box-shadow: inset 0px 0px 1px 1px rgba(255,255,255,0.06); - border-radius: 4px; -} -.menu-category-button-label:ltr { - padding-left: 5px; -} -.menu-category-button-label:rtl { - padding-right: 5px; -} -/* Name and description of the currently hovered item in the menu - * This appears on the bottom right hand corner of the menu*/ -.menu-selected-app-box { - padding-right: 30px; - padding-left: 28px; - text-align: right; - height: 2.2em; -} -.menu-selected-app-box:rtl { - padding-top: 10px; - height: 2.2em; -} -.menu-selected-app-title { - font-weight: bold; -} -.menu-selected-app-description { - max-width: 150px; -} -.menu-top-box { - spacing: 10px; -} -.menu-systembuttons-box { -} -.menu-search-box:ltr { - padding-left: 30px; -} -.menu-search-box:rtl { - padding-right: 30px; -} -#menu-search-entry { - padding: 5px; - border-radius: 4px; - color: rgb(128, 128, 128); - border: 2px solid rgba(245,245,245,0.2); - background-gradient-start: rgba(5,5,6,0.1); - background-gradient-end: rgba(254,254,254,0.1); - background-gradient-direction: vertical; - selected-color: black; - caret-color: rgb(128, 128, 128); - caret-size: 1px; - width: 250px; - transition-duration: 300; - box-shadow: inset 0px 2px 4px rgba(0,0,0,0.6); -} -#menu-search-entry:focus, -#menu-search-entry:hover { - border: 2px solid rgb(136,138,133); - background-gradient-start: rgb(200,200,200); - background-gradient-end: white; - background-gradient-direction: vertical; -} -#menu-search-entry:hover { - transition-duration: 300; -} -#menu-search-entry:focus { - color: rgb(64, 64, 64); - font-weight: bold; - transition-duration: 0; -} -.menu-search-entry-icon { - icon-size: 1em; - color: #8d8f8a; -} -/* Context menu (at the moment only for favorites) */ -.menu-context-menu { -} -/* =================================================================== - * Window list (windowList.js) - * ===================================================================*/ -.window-list-box { - spacing: 2px; - padding-left: 10px; - padding-top: 0px; -} -.window-list-box.vertical { - spacing: 3px; - padding-left: 0px; - padding-right: 0px; - padding-top: 10px; - padding-bottom: 10px; -} -.window-list-box.vertical #appMenuIcon { - padding-top: 3px; -} -.window-list-item-box { - color: rgba(255,255,255,1.0); - background-gradient-direction: vertical; - background-gradient-start: rgba(255,255,255,0.05); - background-gradient-end: rgba(255,255,255,0.2); - box-shadow: inset 0px 0px 1px 1px rgba(170,170,170,0.5); - border-radius: 2px 2px 0px 0px; - transition-duration: 100; - spacing: 0.5em; -} -.window-list-item-box.top { - border-radius: 0px 0px 2px 2px; -} -.window-list-item-box.left { - border-radius: 0px 2px 2px 0px; -} -.window-list-item-box.right { - border-radius: 2px 0px 0px 2px; -} -.window-list-item-box.top, -.window-list-item-box.bottom { - padding: 0 0.5em; -} -.window-list-item-box:active, -.window-list-item-box:checked, -.window-list-item-box:focus, -.window-list-item-box:running { - background-gradient-direction: vertical; - background-gradient-start: rgba(226,226,226,0.5); - background-gradient-end: rgba(122,122,122,0.5); - box-shadow: inset 0px 0px 1px 1px rgba(170,170,170,0.5); -} -.window-list-item-box:hover { - box-shadow: inset 0px 0px 1px 1px rgba(170,170,170,1.0); -} -.window-list-item-demands-attention { - background-gradient-start: rgba(255,52,52,0.5); - background-gradient-end: rgba(255,144,144,0.5); -} - -.window-list-item-box .progress { - background-gradient-direction: vertical; - background-gradient-start: rgba(255,255,255,0.6); - background-gradient-end: rgba(255,255,255,0.3); - border-radius: 2px 2px 0px 0px; - box-shadow: inset 0px 0px 1px 1px rgba(170,170,170,0.5); -} -.panel-top .window-list-item-box .progress { - border-radius: 0px 0px 2px 2px; -} -.panel-left .window-list-item-box .progress { - border-radius: 0px 2px 2px 0px; -} -.panel-right .window-list-item-box .progress { - border-radius: 2px 0px 0px 2px; -} - -.window-list-preview { - background: rgba(80,80,80,0.8); - border: 2px solid #a5a5a5; - border-radius: 8px; - color: white; - text-shadow: 0px 0px 2px black; - padding: 8px; - spacing: 4px; -} - -/* =================================================================== - * Grouped window list (grouped-window-list@cinnamon.org) - * ===================================================================*/ - -.grouped-window-list-box { - spacing: 2px; -} -.grouped-window-list-box.vertical { - spacing: 3px; -} -.grouped-window-list-thumbnail-label { - padding-left: 4px; -} -.grouped-window-list-number-label { - font-size: 10px; - z-index: 99; - text-shadow: 1px 0px 2px black; - color:#fff; - padding: 0; -} -.grouped-window-list-badge { - border-radius: 256px; - background-color: #000000; - margin: 0; -} -.grouped-window-list-button-label { - padding-left: 6px; - padding-right: 6px; -} - -.grouped-window-list-thumbnail-alert { - background: rgba(255,52,52,0.3); -} - -.grouped-window-list-item-box { - color: rgba(255,255,255,1.0); - background-gradient-direction: vertical; - background-gradient-start: rgba(255,255,255,0); - background-gradient-end: rgba(255,255,255,0); - box-shadow: inset 0px 0px 1px 1px rgba(170,170,170,0); - border-radius: 2px 2px 0px 0px; - transition-duration: 100; - spacing: 0.5em; -} -.grouped-window-list-item-box.top { - border-radius: 0px 0px 2px 2px; -} -.grouped-window-list-item-box.left { - border-radius: 0px 2px 2px 0px; -} -.grouped-window-list-item-box.right { - border-radius: 2px 0px 0px 2px; -} -.grouped-window-list-item-box.top, -.grouped-window-list-item-box.bottom { - padding: 0 0.5em; -} - -.grouped-window-list-item-box:checked, -.grouped-window-list-item-box:active:hover { - background-gradient-direction: vertical; - background-gradient-start: rgba(226,226,226,0.5); - background-gradient-end: rgba(122,122,122,0.5); - box-shadow: inset 0px 0px 1px 1px rgba(170,170,170,0.8); -} - -.grouped-window-list-item-box:focus { - background-gradient-direction: vertical; - background-gradient-start: rgba(226,226,226,0.5); - background-gradient-end: rgba(122,122,122,0.3); - box-shadow: inset 0px 0px 1px 1px rgba(170,170,170,0.9); -} - -.grouped-window-list-item-box:active:focus:hover, -.grouped-window-list-item-box:focus:hover { - background-gradient-direction: vertical; - background-gradient-start: rgba(226,226,226,0.3); - background-gradient-end: rgba(122,122,122,0.3); - box-shadow: inset 0px 0px 1px 1px rgba(170,170,170,1.0); -} -.grouped-window-list-item-box:hover { - box-shadow: inset 0px 0px 1px 1px rgba(170,170,170,0.5); -} - -.grouped-window-list-item-box:active { - box-shadow: inset 0px 0px 1px 1px rgba(170,170,170,0.3); -} - -.grouped-window-list-item-demands-attention { - background-gradient-start: rgba(255,52,52,0.5); - background-gradient-end: rgba(255,144,144,0.5); -} - -.grouped-window-list-item-box .progress { - background-gradient-direction: vertical; - background-gradient-start: rgba(255,255,255,0.6); - background-gradient-end: rgba(255,255,255,0.3); - border-radius: 2px 2px 0px 0px; - box-shadow: inset 0px 0px 1px 1px rgba(170,170,170,0.5); -} -.panel-top .grouped-window-list-item-box .progress { - border-radius: 0px 0px 2px 2px; -} -.panel-left .grouped-window-list-item-box .progress { - border-radius: 0px 2px 2px 0px; -} -.panel-right .grouped-window-list-item-box .progress { - border-radius: 2px 0px 0px 2px; -} - -.grouped-window-list-thumbnail-menu { -} -.grouped-window-list-thumbnail-menu .item-box { - background: rgba(80,80,80,0.8); - border: 2px solid #a5a5a5; - color: white; - text-shadow: 0px 0px 2px black; - padding: 10px; - border-radius: 8px; - spacing: 4px; -} -.grouped-window-list-thumbnail-menu .item-box:outlined { - padding: 6px; - border: 2px solid rgba(165, 165, 165, 0.7) -} -.grouped-window-list-thumbnail-menu .item-box:selected { - background: rgba(110,110,110,0.8); -} -.grouped-window-list-thumbnail-menu .thumbnail { - width: 256px; -} -.grouped-window-list-thumbnail-menu .separator { - width: 1px; - background: rgba(255,255,255,0.33); -} - -/* =================================================================== - * Sound Applet (sound@cinnamon.org) - * ===================================================================*/ - -.sound-player StButton { - width: 18px; - height: 18px; - padding: 5px; - color: #aaa; -} - -.sound-player StButton:small { - width: 16px; - height: 16px; -} - -.sound-player StButton:small StIcon { - icon-size: 1.2em; -} - -.sound-player StButton StIcon { - icon-size: 1.5em; -} - -.sound-player StButton:hover, .sound-player StButton:active { - color: #fff; -} - -.sound-player .slider { - height: 0.5em; - -slider-height: 0.5em; - -slider-background-color: #3c3c3c; - -slider-border-color: rgba(0,0,0,0); - -slider-active-background-color: #a5a5a5; - -slider-active-border-color: rgba(0,0,0,0); - -slider-border-width: 0px; - -slider-handle-radius: 0px; -} - -.sound-player StBoxLayout { - spacing: 0.5em; -} - -.sound-player>StBoxLayout { - padding: 0 16px 8px; -} - -.sound-player-overlay { - width: 300px; - padding: 12px 16px; - spacing: 0.5em; - background-color: rgba(80,80,80,0.9); - color: #ffffff; - border-top: 2px solid #a5a5a5; -} - -.sound-player-overlay StButton { - border-radius: 5px; - padding: 8px; -} - -.sound-player-overlay StButton > StIcon { - icon-size: 16px; -} - -.sound-player-overlay StBoxLayout { - padding-top: 2px; -} - -.sound-player-generic-coverart { - background: rgba(0,0,0,0.2); -} - -/* =================================================================== - * Spacer applet - * ===================================================================*/ -.spacer-box { - border-radius: 1px; - border: 1px solid transparent; -} - -.spacer-box:highlight { - background-color: #aa5555; -} - -.spacer-box.vertical { -} - -.spacer-box.edit-mode { - border-radius: 1px; - border: 1px symbolic; -} - -/* =================================================================== - * Workspace Switcher applet (workspaceSwitcher.js) - * ===================================================================*/ -/* Controls the styling when using the "Simple buttons" option */ -.panel-top .workspace-switcher, -.panel-bottom .workspace-switcher { - padding: 0 3px; -} - -.panel-left .workspace-switcher, -.panel-right .workspace-switcher { - padding: 3px; -} - -.workspace-button { - color: #cccccc; - border: 1px; - border-color: #a6a6a6; - padding: 0 8px; - transition-duration: 300; -} - -.vertical .workspace-button { - padding: 4px 0; -} - -.workspace-button:outlined { - background: #cccccc; - color: #555555; - box-shadow: inset 0px 0px 8px 1px rgba(255,255,255, 0.7); -} - -.workspace-button:shaded { - color: #13191c; -} - -/* Controls the style when using the "Visual representation" option */ -.workspace-graph { - padding: 3px; - spacing: 3px; -} - -.workspace-graph .workspace { - border: 1px solid #666; - background-gradient-direction: vertical; - background-gradient-start: #222; - background-gradient-end: #4d4d4d; -} - -.workspace-graph .workspace:active { - border: 1px solid #ccc; - background-gradient-direction: vertical; - background-gradient-start: #111; - background-gradient-end: #3d3d3d; -} - -.workspace-graph .workspace .windows { - -active-window-background: rgba(140, 140, 140, 1.0); - -active-window-border: rgba(0, 0, 0, 0.7); - -inactive-window-background: rgba(140, 140, 140, 1.0); - -inactive-window-border: rgba(0, 0, 0, 0.7); -} - -.workspace-graph .workspace:active .windows { - -active-window-background: rgba(255, 255, 255, 1.0); - -active-window-border: rgba(0, 0, 0, 0.9); - -inactive-window-background: rgba(140, 140, 140, 1.0); - -inactive-window-border: rgba(0, 0, 0, 0.7); -} - -/* =================================================================== - * Panel Launchers Applet (panelLaunchers.js) - * ===================================================================*/ -.panel-launchers { - padding-left: 7px; - spacing: 2px; -} - -.panel-launchers.vertical { - padding-top: 2px; - padding-bottom: 2px; - padding-left: 0px; - padding-right: 0px; - spacing: 3px; -} - -.launcher { - padding-left: 1px; - padding-right: 1px; - border-bottom-width: 1px; - transition-duration: 300; -} - -.launcher .icon-box { - padding-top: 2px; -} - -.panel-launchers.vertical .launcher .icon-box { - padding-top: 0; -} - -.panel-launchers .launcher:hover { - background-gradient-direction: vertical; - background-gradient-start: rgba(255,255,255,0.0); - background-gradient-end: rgba(255,255,255,0.2); - border: 0px solid rgba(255,255,255,0.5); - border-bottom-width: 1px; -} - -/* =================================================================== - * Overview corner - * ===================================================================*/ -#overview-corner { - background-image: url("overview.png"); -} -#overview-corner:hover { - background-image: url("overview-hover.png"); -} -/* =================================================================== - * Applets (applet.js) - * ===================================================================*/ -.applet-separator { - padding: 5px 4px; -} -.applet-separator-line { - width: 2px; - background: rgba(255,255,255,0.5); -} - -.applet-separator-line-vertical { - border: 0px solid rgba(255,255,255,0.5); - border-bottom-width: 2px; -} - -.applet-cornerbar-box { - padding: 4px 4px; - background: rgba(255,255,255,0); -} - -.applet-cornerbar { - width: 8px; - background: rgba(255,255,255,0.3); -} - -.applet-cornerbar.vertical { - height: 8px; -} - -.applet-cornerbar-box:hover > .applet-cornerbar { - background: rgba(255,255,255,0.4); -} - - -.applet-box { - padding-left: 3px; - padding-right: 3px; - color: #ccc; - text-shadow: black 0px 0px 2px; - transition-duration: 300; - text-align: center; -} -.panel-top .applet-box, -.panel-bottom .applet-box { - spacing: 3px; -} -.applet-box:checked, -.applet-box:hover { - color: #fff; -} -.applet-box.vertical { - padding-left: 0px; - padding-right: 0px; - padding-top: 3px; - padding-bottom: 3px; -} -.applet-box.vertical:hover { -} -.applet-box:highlight { - background-color: #aa5555; -} -.applet-label { - font-weight: bold; - color: #ccc; -} -.applet-box:checked > .applet-label, -.applet-box:hover > .applet-label { - color: #fff; - text-shadow: white 0px 0px 5px; -} -.applet-box.vertical:hover > .applet-label { -} -.applet-icon { /* symbolic icons will use system-status-icon instead */ - color: #ccc; - icon-size: 22px; -} -.applet-box:checked .applet-icon, -.applet-box:hover .applet-icon { - color: #fff; - icon-shadow: white 0px 0px 3px; -} -.applet-box.vertical:hover .applet-icon { -} -/* =================================================================== - * Desklets (desklet.js) - * ===================================================================*/ -.desklet { - color: #fff; -} - -.desklet:highlight, .desklet:highlight-with-borders, .desklet:highlight-with-borders-and-header { - background-color: #aa5555; -} - -.desklet-with-borders { - border: 2px solid #a5a5a5; - background-color: rgba(80, 80, 80, 0.8); - color: #fff; - border-radius-bottomleft: 12px; - border-radius-bottomright: 12px; - border-radius-topleft: 12px; - border-radius-topright: 12px; -} - -.desklet-with-borders-and-header { - border: 2px solid #a5a5a5; - background-color: rgba(80, 80, 80, 0.8); - color: #fff; - border-top: 1px; - border-radius-bottomleft: 12px; - border-radius-bottomright: 12px; -} - -.desklet-header { - border-radius-topleft: 12px; - border-radius-topright: 12px; - border: 2px solid #a5a5a5; - border-bottom: 0px; - background-color: rgba(80, 80, 80, 0.8); - color: #fff; - padding: 6px; -} - -.desklet-drag-placeholder { - border: 2px solid #6daa00; - background-color: rgba(109,170, 0, 0.3); -} - -/* =================================================================== - * Clock Desklet (desklet.js) - * ===================================================================*/ -.clock-desklet-label { -} - -.expo-workspaces-name-entry { - padding: 5px; - border-radius: 4px; - color: rgb(200, 200, 200); - border: 2px solid rgb(136,138,133); - background-gradient-start: rgb(128,128,128); - background-gradient-end: rgb(85,85,85); - background-gradient-direction: vertical; - selected-color: black; - caret-color: rgb(128, 128, 128); - caret-size: 1px; - min-width: 80px; - height: 1.4em; - box-shadow: inset 0px 2px 4px rgba(0,0,0,0.6); -} - -.expo-workspaces-name-entry#selected { - background-gradient-start: rgb(200,200,200); - background-gradient-end: white; - font-weight: bold; - color: rgb(0, 0, 0); -} - -.expo-workspaces-name-entry:focus { - color: rgb(0, 0, 0); - font-weight: bold; - font-style: italic; - transition-duration: 300; -} - -/* =================================================================== - * Notification Applet - * ===================================================================*/ - -.notification-applet-padding { - padding: .5em 1em; -} - -.notification-applet-container { - max-height: 100px; -} - -/* Check Boxes */ -.check-box CinnamonGenericContainer { - spacing: .2em; -} - -.check-box StBin, -.check-box:focus StBin { - width: 16px; - height: 16px; - background-image: url("checkbox-off.svg"); -} - -.check-box:checked StBin, -.check-box:focus:checked StBin { - background-image: url("checkbox.svg"); -} - -.check-box StLabel { - font-weight: normal; -} - -.radiobutton CinnamonGenericContainer { - spacing: .2em; - height: 18px; - padding-top: 2px; -} - -.radiobutton StBin, -.radiobutton:focus StBin { - width: 16px; - height: 16px; - background-image: url("radiobutton-off.svg"); - border-radius: 15px; -} - -.radiobutton:checked StBin, -.radiobutton:focus:checked StBin { - background-image: url("radiobutton.svg"); -} - -.radiobutton StLabel { - padding-top: 4px; - box-shadow: none; -} - -.flashspot { - background-color: white; -} - -/* Media keys OSD popup */ -.osd-window { - background: rgba(80,80,80,0.8); - border: 2px solid #a5a5a5; - border-radius: 8px; - padding: 20px; - color: white; - spacing: 1em; -} - -.osd-window .level { - height: 0.7em; - border-radius: 0.3em; - background-color: rgba(190,190,190,0.2); -} - -.osd-window .level-bar { - border-radius: 0.3em; - background-color: rgba(190,190,190,0.8); -} - -.tile-preview, -.tile-hud { - background-color: rgba(85, 85, 85, 0.5); - border: 2px solid rgba(134, 134, 134, 0.8); -} - -.tile-preview.snap, -.tile-hud.snap { - background-color: rgba(134, 134, 170, 0.5); - border: 2px solid rgba(85, 85, 85, 0.8); -} - -.tile-hud:top { - border-top-width: 0px; - border-radius: 0px 0px 8px 8px; -} - -.tile-hud:bottom { - border-bottom-width: 0px; - border-radius: 8px 8px 0px 0px; -} - -.tile-hud:left { - border-left-width: 0px; - border-radius: 0px 8px 8px 0px; -} - -.tile-hud:right { - border-right-width: 0px; - border-radius: 8px 0px 0px 8px; -} - -.tile-hud:top-left { - border-top-width: 0px; - border-left-width: 0px; - border-radius: 0px 0px 8px 0px; -} - -.tile-hud:top-right { - border-top-width: 0px; - border-right-width: 0px; - border-radius: 0px 0px 0px 8px; -} - -.tile-hud:bottom-left { - border-bottom-width: 0px; - border-left-width: 0px; - border-radius: 0px 8px 0px 0px; -} - -.tile-hud:bottom-right { - border-bottom-width: 0px; - border-right-width: 0px; - border-radius: 8px 0px 0px 0px; -} -/* =================================================================== - * Systray Applet - * - * .systray is for theming to be applied to the systray as a whole - * .applet-box is used for indicators (not tray icons) within the systray - * tray icons are not themed - * ===================================================================*/ -.systray { - spacing: 5px; -} - -/* Pointer accessibility notifications */ -.pie-timer { - width: 30px; - height: 30px; - -pie-border-width: 1px; - -pie-border-color: rgba(200, 200, 200, 0.8); - -pie-background-color: rgba(140, 140, 140, 0.6);; -} - -.user-icon { - border: 2px solid #868686; - border-radius: 99px; -} diff --git a/data/theme/close-window-hover.svg b/data/theme/close-window-hover.svg deleted file mode 100644 index 65df4c2722..0000000000 --- a/data/theme/close-window-hover.svg +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/theme/close-window.svg b/data/theme/close-window.svg deleted file mode 100644 index 28d3549faf..0000000000 --- a/data/theme/close-window.svg +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/theme/close.svg b/data/theme/close.svg index cb6b4cf4dc..0fb532e32d 100644 --- a/data/theme/close.svg +++ b/data/theme/close.svg @@ -1,10 +1,102 @@ - - - - - - - - - + + +image/svg+xml diff --git a/data/theme/meson.build b/data/theme/meson.build new file mode 100644 index 0000000000..b02e5c18b0 --- /dev/null +++ b/data/theme/meson.build @@ -0,0 +1,3 @@ +sassc = find_program('pysassc') + +run_command('parse-sass.sh', check: true) diff --git a/data/theme/overview-hover.png b/data/theme/overview-hover.png deleted file mode 100644 index 75673f9cf4..0000000000 Binary files a/data/theme/overview-hover.png and /dev/null differ diff --git a/data/theme/overview.png b/data/theme/overview.png deleted file mode 100644 index aed443ea00..0000000000 Binary files a/data/theme/overview.png and /dev/null differ diff --git a/data/theme/parse-sass.sh b/data/theme/parse-sass.sh new file mode 100755 index 0000000000..3313971158 --- /dev/null +++ b/data/theme/parse-sass.sh @@ -0,0 +1,3 @@ +#! /bin/bash + +pysassc ./cinnamon-sass/cinnamon.scss cinnamon.css diff --git a/data/theme/process-working.svg b/data/theme/process-working.svg deleted file mode 100644 index f2ba6f904e..0000000000 --- a/data/theme/process-working.svg +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/theme/radio-off.svg b/data/theme/radio-off.svg new file mode 100644 index 0000000000..64b0eafb94 --- /dev/null +++ b/data/theme/radio-off.svg @@ -0,0 +1,49 @@ + + + + + + + + diff --git a/data/theme/radio.svg b/data/theme/radio.svg new file mode 100644 index 0000000000..fb9d4ae7b1 --- /dev/null +++ b/data/theme/radio.svg @@ -0,0 +1,55 @@ + + + + + + + + + diff --git a/data/theme/radiobutton-off.svg b/data/theme/radiobutton-off.svg deleted file mode 100644 index 2072b8bbca..0000000000 --- a/data/theme/radiobutton-off.svg +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/data/theme/radiobutton.svg b/data/theme/radiobutton.svg deleted file mode 100644 index b50864af60..0000000000 --- a/data/theme/radiobutton.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/data/theme/scroll-hhandle.svg b/data/theme/scroll-hhandle.svg deleted file mode 100644 index cd4d7969e5..0000000000 --- a/data/theme/scroll-hhandle.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/data/theme/scroll-vhandle.svg b/data/theme/scroll-vhandle.svg deleted file mode 100644 index 168e75c0d9..0000000000 --- a/data/theme/scroll-vhandle.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/data/theme/thumbnail.png b/data/theme/thumbnail.png index 859700597c..64a74d198c 100644 Binary files a/data/theme/thumbnail.png and b/data/theme/thumbnail.png differ diff --git a/data/theme/toggle-off-intl.svg b/data/theme/toggle-off-intl.svg deleted file mode 100644 index a783b80ba3..0000000000 --- a/data/theme/toggle-off-intl.svg +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/theme/toggle-off-us.svg b/data/theme/toggle-off-us.svg deleted file mode 100644 index c6ec60d34f..0000000000 --- a/data/theme/toggle-off-us.svg +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/theme/toggle-off.svg b/data/theme/toggle-off.svg new file mode 100644 index 0000000000..83c8f563ee --- /dev/null +++ b/data/theme/toggle-off.svg @@ -0,0 +1,68 @@ + + + + + + + + + + diff --git a/data/theme/toggle-on-intl.svg b/data/theme/toggle-on-intl.svg deleted file mode 100644 index 01b987d4c6..0000000000 --- a/data/theme/toggle-on-intl.svg +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/theme/toggle-on-us.svg b/data/theme/toggle-on-us.svg deleted file mode 100644 index 0a3a4cd9ae..0000000000 --- a/data/theme/toggle-on-us.svg +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/theme/toggle-on.svg b/data/theme/toggle-on.svg new file mode 100644 index 0000000000..f20db6f92a --- /dev/null +++ b/data/theme/toggle-on.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + diff --git a/data/theme/trash-icon.png b/data/theme/trash-icon.png deleted file mode 100644 index 7cee0c64de..0000000000 Binary files a/data/theme/trash-icon.png and /dev/null differ diff --git a/data/theme/trash-icon.svg b/data/theme/trash-icon.svg new file mode 100644 index 0000000000..82b73ed433 --- /dev/null +++ b/data/theme/trash-icon.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/debian/control b/debian/control index b9812a1276..7023f3e0c2 100644 --- a/debian/control +++ b/debian/control @@ -31,6 +31,7 @@ Build-Depends: libstartup-notification0-dev (>= 0.11), libxapp-dev (>= 2.6.0), meson, + pysassc, python3:any, Standards-Version: 3.9.5 Homepage: https://projects.linuxmint.com/cinnamon/ diff --git a/files/usr/share/cinnamon/applets/network@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/network@cinnamon.org/applet.js index 158aee185a..eb6931a4b4 100644 --- a/files/usr/share/cinnamon/applets/network@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/network@cinnamon.org/applet.js @@ -649,6 +649,7 @@ NMDevice.prototype = { } this._activeConnectionItem = new PopupMenu.PopupMenuItem(title, { reactive: false }); this._activeConnectionItem.setShowDot(true); + this._activeConnectionItem.actor.add_style_class_name('popup-device-menu-item'); }, _deviceStateChanged: function(device, newstate, oldstate, reason) { @@ -894,6 +895,7 @@ NMDeviceModem.prototype = { if (!this.mobileDevice.operator_name) this._operatorItem.actor.hide(); this.section.addMenuItem(this._operatorItem); + this._operatorItem.actor.add_style_class_name('popup-device-menu-item'); } NMDevice.prototype._createSection.call(this); @@ -1603,6 +1605,7 @@ NMDeviceWireless.prototype = { { reactive: false }); } this._activeConnectionItem.setShowDot(true); + this._activeConnectionItem.actor.add_style_class_name('popup-device-menu-item'); }, _createAutomaticConnection: function(apObj) { diff --git a/files/usr/share/cinnamon/cinnamon-settings/modules/cs_notifications.py b/files/usr/share/cinnamon/cinnamon-settings/modules/cs_notifications.py index 24b4199c37..ab6746cca3 100755 --- a/files/usr/share/cinnamon/cinnamon-settings/modules/cs_notifications.py +++ b/files/usr/share/cinnamon/cinnamon-settings/modules/cs_notifications.py @@ -22,13 +22,6 @@ aliquam ullamcorper. """ -MEDIA_KEYS_OSD_SIZES = [ - ("disabled", _("Disabled")), - ("small", _("Small")), - ("medium", _("Medium")), - ("large", _("Large")) -] - NOTIFICATION_DISPLAY_SCREENS = [ ("primary-screen", _("Primary monitor")), ("active-screen", _("Active monitor")), @@ -84,8 +77,8 @@ def on_module_selected(self): settings = page.add_section(_("Media keys OSD")) - combo = GSettingsComboBox(_("Media keys OSD size"), "org.cinnamon", "show-media-keys-osd", MEDIA_KEYS_OSD_SIZES) - settings.add_row(combo) + switch = GSettingsSwitch(_("Show media keys OSD"), "org.cinnamon", "show-media-keys-osd") + settings.add_row(switch) def send_test(self, widget): n = Notify.Notification.new("This is a test notification", content, "dialog-warning") diff --git a/js/misc/util.js b/js/misc/util.js index 7bf259ab96..6eb92dd078 100644 --- a/js/misc/util.js +++ b/js/misc/util.js @@ -14,8 +14,14 @@ const Gio = imports.gi.Gio; const Gtk = imports.gi.Gtk; const GObject = imports.gi.GObject; const Gir = imports.gi.GIRepository; +const Clutter = imports.gi.Clutter; const Mainloop = imports.mainloop; const Main = imports.ui.main; +const Params = imports.misc.params; + +const WIGGLE_OFFSET = 6; +const WIGGLE_DURATION = 65; +const N_WIGGLES = 3; // http://daringfireball.net/2010/07/improved_regex_for_matching_urls const _balancedParens = '\\([^\\s()<>]+\\)'; @@ -729,3 +735,37 @@ function splitByGlyph(str) { } return glyphs; } + +function wiggle(actor, params) { + params = Params.parse(params, { + offset: WIGGLE_OFFSET, + duration: WIGGLE_DURATION, + wiggleCount: N_WIGGLES, + }); + actor.translation_x = 0; + + // Accelerate before wiggling + actor.ease({ + translation_x: -params.offset, + duration: params.duration, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => { + // Wiggle + actor.ease({ + translation_x: params.offset, + duration: params.duration, + mode: Clutter.AnimationMode.LINEAR, + repeatCount: params.wiggleCount, + autoReverse: true, + onComplete: () => { + // Decelerate and return to the original position + actor.ease({ + translation_x: 0, + duration: params.duration, + mode: Clutter.AnimationMode.EASE_IN_QUAD, + }); + } + }); + } + }); +} diff --git a/js/ui/accessibility.js b/js/ui/accessibility.js index 322c80b6a7..214a6328a7 100644 --- a/js/ui/accessibility.js +++ b/js/ui/accessibility.js @@ -131,19 +131,24 @@ A11yHandler.prototype = { popup_state_osd: function(key, state) { let icon = null; + let text = null; switch (key) { case CAPS: icon = Gio.ThemedIcon.new(state ? "cinnamon-caps-lock-symbolic" : "cinnamon-caps-lock-off-symbolic"); + text = state ? _("Caps Lock On"): + _("Caps Lock Off"); break; case NUM: icon = Gio.ThemedIcon.new(state ? "cinnamon-num-lock-symbolic" : "cinnamon-num-lock-off-symbolic"); + text = state ? _("Number Lock On"): + _("Number Lock Off"); break; } - Main.osdWindowManager.show(-1, icon, undefined); + Main.osdWindowManager.show(-1, icon, text, null); }, play_state_sound: function(key, state) { diff --git a/js/ui/appSwitcher/classicSwitcher.js b/js/ui/appSwitcher/classicSwitcher.js index 2c53434972..4af8c01c14 100644 --- a/js/ui/appSwitcher/classicSwitcher.js +++ b/js/ui/appSwitcher/classicSwitcher.js @@ -67,7 +67,7 @@ ClassicSwitcher.prototype = { this._iconsEnabled = true; this._showThumbnails = this._thumbnailsEnabled && !this._iconsEnabled; - this._showArrows = this._thumbnailsEnabled && this._iconsEnabled; + this._showIconAndThumbnails = this._thumbnailsEnabled && this._iconsEnabled; this._updateList(0); @@ -188,7 +188,7 @@ ClassicSwitcher.prototype = { this.actor.remove_actor(this._appList.actor); this._appList.actor.destroy(); } - this._appList = new AppList(this._windows, this._showThumbnails, this._showArrows, this._activeMonitor); + this._appList = new AppList(this._windows, this._showThumbnails, this._activeMonitor); this.actor.add_actor(this._appList.actor); if (!this._iconsEnabled && !this._thumbnailsEnabled) { this._appList.actor.hide(); @@ -233,7 +233,7 @@ ClassicSwitcher.prototype = { this._thumbnailTimeoutId = 0; } - if (this._showArrows) { + if (this._showIconAndThumbnails) { this._thumbnailTimeoutId = Mainloop.timeout_add( THUMBNAIL_POPUP_TIME, Lang.bind(this, function() { @@ -755,7 +755,7 @@ function AppList() { AppList.prototype = { __proto__ : SwitcherList.prototype, - _init : function(windows, showThumbnails, showArrows, activeMonitor) { + _init : function(windows, showThumbnails, activeMonitor) { SwitcherList.prototype._init.call(this, true, activeMonitor); // Construct the AppIcons, add to the popup @@ -767,7 +767,6 @@ AppList.prototype = { } this.icons = []; - this._arrows = []; for (let i = 0; i < workspaceIcons.length; i++) this._addIcon(workspaceIcons[i]); if (workspaceIcons.length > 0 && otherIcons.length > 0) @@ -777,7 +776,6 @@ AppList.prototype = { this._curApp = -1; this._iconSize = 0; - this._showArrows = showArrows; this._mouseTimeOutId = 0; this._activeMonitor = activeMonitor; }, @@ -825,27 +823,6 @@ AppList.prototype = { alloc.natural_size = height; }, - _allocate: function (actor, box, flags) { - // Allocate the main list items - SwitcherList.prototype._allocate.call(this, actor, box, flags); - - if (this._showArrows) { - let arrowHeight = Math.floor(this.actor.get_theme_node().get_padding(St.Side.BOTTOM) / 3); - let arrowWidth = arrowHeight * 2; - - // Now allocate each arrow underneath its item - let childBox = new Clutter.ActorBox(); - for (let i = 0; i < this._items.length; i++) { - let itemBox = this._items[i].allocation; - childBox.x1 = Math.floor(itemBox.x1 + (itemBox.x2 - itemBox.x1 - arrowWidth) / 2); - childBox.x2 = childBox.x1 + arrowWidth; - childBox.y1 = itemBox.y2 + arrowHeight; - childBox.y2 = childBox.y1 + arrowHeight; - this._arrows[i].allocate(childBox, flags); - } - } - }, - // We override SwitcherList's _onItemEnter method to delay // activation when the thumbnail list is open _onItemEnter: function (index) { @@ -861,31 +838,9 @@ AppList.prototype = { this._itemEntered(index); }, - // We override SwitcherList's highlight() method to also deal with - // the AppList->ThumbnailList arrows. - highlight : function(n, justOutline) { - if (this._curApp != -1) { - this._arrows[this._curApp].hide(); - } - - SwitcherList.prototype.highlight.call(this, n, justOutline); - this._curApp = n; - - if (n != -1 && this._showArrows) { - this._arrows[n].show(); - } - }, - _addIcon : function(appIcon) { this.icons.push(appIcon); this.addItem(appIcon.actor, appIcon.label); - - let n = this._arrows.length; - let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' }); - arrow.connect('repaint', function() { _drawArrow(arrow, St.Side.BOTTOM); }); - this._list.add_actor(arrow); - this._arrows.push(arrow); - arrow.hide(); } }; diff --git a/js/ui/barLevel.js b/js/ui/barLevel.js new file mode 100644 index 0000000000..43b15e0bc3 --- /dev/null +++ b/js/ui/barLevel.js @@ -0,0 +1,260 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Clutter = imports.gi.Clutter; +const GObject = imports.gi.GObject; +const St = imports.gi.St; + +var BarLevel = GObject.registerClass({ + Properties: { + 'value': GObject.ParamSpec.double( + 'value', 'value', 'value', + GObject.ParamFlags.READWRITE, + 0, 2, 0), + 'maximum-value': GObject.ParamSpec.double( + 'maximum-value', 'maximum-value', 'maximum-value', + GObject.ParamFlags.READWRITE, + 1, 2, 1), + 'amplify-start': GObject.ParamSpec.double( + 'amplify-start', 'amplify-start', 'amplify-start', + GObject.ParamFlags.READWRITE, + 1, 2, 1), + }, +}, class BarLevel extends St.DrawingArea { + _init(params) { + this._maxValue = 1; + this._value = 0; + this._amplifyStart = 1; + this._barLevelWidth = 0; + this._barLevelHeight = 0; + + this._amplifySeparatorWidth = 0; + + this._barLevelColor = null; + this._barLevelActiveColor = null; + this._barLevelAmplifyColor = null; + + let defaultParams = { + style_class: 'barlevel', + }; + super._init(Object.assign(defaultParams, params)); + this.connect('notify::allocation', () => { + this._barLevelWidth = this.allocation.get_width(); + }); + } + + get value() { + return this._value; + } + + set value(value) { + value = Math.max(Math.min(value, this._maxValue), 0); + + if (this._value == value) + return; + + this._value = value; + this.notify('value'); + this.queue_repaint(); + } + + get maximum_value() { + return this._maxValue; + } + + set maximum_value(value) { + value = Math.max(value, 1); + + if (this._maxValue == value) + return; + + this._maxValue = value; + this._amplifyStart = Math.min(this._amplifyStart, this._maxValue); + this.notify('maximum-value'); + this.queue_repaint(); + } + + get amplify_start() { + return this._amplifyStart; + } + + set amplify_start(value) { + if (this._amplifyStart == value) + return; + + if (value > this._maxValue) { + throw new Error(`Tried to set amplify value to ${value}, ` + + `which is a number greater than the maximum allowed value ${this._maxValue}`); + } + + this._amplifyStart = value; + this.notify('amplify-start'); + this.queue_repaint(); + } + + vfunc_style_changed() { + const themeNode = this.get_theme_node(); + this._barLevelHeight = themeNode.get_length('-barlevel-height'); + this._amplifySeparatorWidth = + themeNode.get_length('-barlevel-amplify-separator-width'); + + this._barLevelColor = themeNode.get_color('-barlevel-background-color'); + this._barLevelActiveColor = themeNode.get_color('-barlevel-active-background-color'); + this._barLevelAmplifyColor = themeNode.get_color('-barlevel-amplify-color'); + + super.vfunc_style_changed(); + } + + vfunc_repaint() { + let cr = this.get_context(); + let themeNode = this.get_theme_node(); + let [width, height] = this.get_surface_size(); + const rtl = this.get_direction() === St.TextDirection.RTL; + + const barLevelBorderRadius = Math.min(width, this._barLevelHeight) / 2; + let fgColor = themeNode.get_foreground_color(); + + const TAU = Math.PI * 2; + + let endX = 0; + if (this._maxValue > 0) { + let progress = this._value / this._maxValue; + if (rtl) + progress = 1 - progress; + endX = barLevelBorderRadius + (width - 2 * barLevelBorderRadius) * progress; + } + + let amplifyRatio = this._amplifyStart / this._maxValue; + if (rtl) + amplifyRatio = 1 - amplifyRatio; + let amplifySeparatorX = barLevelBorderRadius + (width - 2 * barLevelBorderRadius) * amplifyRatio; + + let amplifyActive = this._amplifyStart !== this._maxValue; + const amplifySeparatorWidth = amplifyActive + ? this._amplifySeparatorWidth : 0; + + let xcArcStart = barLevelBorderRadius; + let xcArcEnd = width - xcArcStart; + if (rtl) + [xcArcStart, xcArcEnd] = [xcArcEnd, xcArcStart]; + + /* background bar */ + if (!rtl) + cr.arc(xcArcEnd, height / 2, barLevelBorderRadius, TAU * (3 / 4), TAU * (1 / 4)); + else + cr.arcNegative(xcArcEnd, height / 2, barLevelBorderRadius, TAU * (3 / 4), TAU * (1 / 4)); + cr.lineTo(endX, (height + this._barLevelHeight) / 2); + cr.lineTo(endX, (height - this._barLevelHeight) / 2); + cr.lineTo(xcArcEnd, (height - this._barLevelHeight) / 2); + Clutter.cairo_set_source_color(cr, this._barLevelColor); + cr.fillPreserve(); + cr.fill(); + + /* normal progress bar */ + let x = 0; + if (!rtl) { + x = Math.min(endX, amplifySeparatorX - amplifySeparatorWidth / 2); + cr.arc(xcArcStart, height / 2, barLevelBorderRadius, TAU * (1 / 4), TAU * (3 / 4)); + } else { + x = Math.max(endX, amplifySeparatorX + amplifySeparatorWidth / 2); + cr.arcNegative(xcArcStart, height / 2, barLevelBorderRadius, TAU * (1 / 4), TAU * (3 / 4)); + } + cr.lineTo(x, (height - this._barLevelHeight) / 2); + cr.lineTo(x, (height + this._barLevelHeight) / 2); + cr.lineTo(xcArcStart, (height + this._barLevelHeight) / 2); + if (this._value > 0) + Clutter.cairo_set_source_color(cr, this._barLevelActiveColor); + cr.fillPreserve(); + cr.fill(); + + /* amplify progress barLevel */ + if (!rtl) + x = Math.min(endX, amplifySeparatorX) + amplifySeparatorWidth / 2; + else + x = Math.max(endX, amplifySeparatorX) - amplifySeparatorWidth / 2; + if (this._value > this._amplifyStart) { + cr.moveTo(x, (height - this._barLevelHeight) / 2); + cr.lineTo(endX, (height - this._barLevelHeight) / 2); + cr.lineTo(endX, (height + this._barLevelHeight) / 2); + cr.lineTo(x, (height + this._barLevelHeight) / 2); + cr.lineTo(x, (height - this._barLevelHeight) / 2); + Clutter.cairo_set_source_color(cr, this._barLevelAmplifyColor); + cr.fillPreserve(); + cr.fill(); + } + + /* end progress bar arc */ + if (this._value > 0) { + if (this._value <= this._amplifyStart) + Clutter.cairo_set_source_color(cr, this._barLevelActiveColor); + else + Clutter.cairo_set_source_color(cr, this._barLevelAmplifyColor); + if (!rtl) { + cr.arc(endX, height / 2, barLevelBorderRadius, TAU * (3 / 4), TAU * (1 / 4)); + cr.lineTo(Math.floor(endX), (height + this._barLevelHeight) / 2); + cr.lineTo(Math.floor(endX), (height - this._barLevelHeight) / 2); + } else { + cr.arcNegative(endX, height / 2, barLevelBorderRadius, TAU * (3 / 4), TAU * (1 / 4)); + cr.lineTo(Math.ceil(endX), (height + this._barLevelHeight) / 2); + cr.lineTo(Math.ceil(endX), (height - this._barLevelHeight) / 2); + } + cr.lineTo(endX, (height - this._barLevelHeight) / 2); + cr.fillPreserve(); + } + + /* draw amplify separator */ + if (amplifyActive) { + cr.moveTo(amplifySeparatorX - amplifySeparatorWidth / 2, (height - this._barLevelHeight) / 2); + cr.lineTo(amplifySeparatorX + amplifySeparatorWidth / 2, (height - this._barLevelHeight) / 2); + cr.lineTo(amplifySeparatorX + amplifySeparatorWidth / 2, (height + this._barLevelHeight) / 2); + cr.lineTo(amplifySeparatorX - amplifySeparatorWidth / 2, (height + this._barLevelHeight) / 2); + cr.lineTo(amplifySeparatorX - amplifySeparatorWidth / 2, (height - this._barLevelHeight) / 2); + if (this._value <= this._amplifyStart) + Clutter.cairo_set_source_color(cr, fgColor); + else + Clutter.cairo_set_source_color(cr, this._barLevelColor); + cr.fill(); + } + + cr.$dispose(); + } + + vfunc_get_preferred_height(_forWidth) { + const themeNode = this.get_theme_node(); + const height = this._getPreferredHeight(); + return themeNode.adjust_preferred_height(height, height); + } + + vfunc_get_preferred_width(_forHeight) { + const themeNode = this.get_theme_node(); + const width = this._getPreferredWidth(); + return themeNode.adjust_preferred_width(width, width); + } + + _getPreferredHeight() { + return this._barLevelHeight; + } + + _getPreferredWidth() { + return this._amplifySeparatorWidth; + } + + _getCurrentValue() { + return this._value; + } + + _getAmplifyStart() { + return this._amplifyStart; + } + + _getMinimumValue() { + return 0; + } + + _getMaximumValue() { + return this._maxValue; + } + + _setCurrentValue(_actor, value) { + this._value = value; + } +}); diff --git a/js/ui/cinnamonDBus.js b/js/ui/cinnamonDBus.js index 4048a43cfd..cd15027ff3 100644 --- a/js/ui/cinnamonDBus.js +++ b/js/ui/cinnamonDBus.js @@ -258,7 +258,7 @@ CinnamonDBus.prototype = { if (params['icon']) icon = Gio.Icon.new_for_string(params['icon']); - Main.osdWindowManager.show(monitorIndex, icon, params['level'], false); + Main.osdWindowManager.show(monitorIndex, icon, params['label'], params['level'], false); }, FlashArea: function(x, y, width, height) { diff --git a/js/ui/dialog.js b/js/ui/dialog.js new file mode 100644 index 0000000000..2e8fdcfdc0 --- /dev/null +++ b/js/ui/dialog.js @@ -0,0 +1,272 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Clutter = imports.gi.Clutter; +const St = imports.gi.St; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; +const Meta = imports.gi.Meta; +const Pango = imports.gi.Pango; + +function _setLabel(label, value) { + label.set({ + text: value || '', + visible: value !== null, + }); +} + +var Dialog = GObject.registerClass( +class Dialog extends St.Widget { + + _init(parentActor, styleClass) { + super._init({ layout_manager: new Clutter.BinLayout() }); + this.connect('destroy', this._onDestroy.bind(this)); + + this._initialKeyFocus = null; + this._initialKeyFocusDestroyId = 0; + this._pressedKey = null; + this._buttonKeys = {}; + this._createDialog(); + this.add_child(this._dialog); + + if (styleClass != null) + this._dialog.add_style_class_name(styleClass); + + this._parentActor = parentActor; + this._eventId = this._parentActor.connect('event', this._modalEventHandler.bind(this)); + this._parentActor.add_child(this); + } + + _createDialog() { + this._dialog = new St.BoxLayout({ + style_class: 'dialog', + important: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER, + vertical: true + }); + + // modal dialogs are fixed width and grow vertically; set the request + // mode accordingly so wrapped labels are handled correctly during + // size requests. + this._dialog.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); + this._dialog.request_mode = Clutter.RequestMode.HEIGHT_FOR_WIDTH; + + this.contentLayout = new St.BoxLayout({ + vertical: true, + style_class: "dialog-content-box", + important: true + }); + this._dialog.add(this.contentLayout, { + expand: true, + x_fill: true, + y_fill: true, + x_align: St.Align.MIDDLE, + y_align: St.Align.START + }); + + this.buttonLayout = new St.Widget ({ + layout_manager: new Clutter.BoxLayout({ + homogeneous: true, + spacing: 12, + }), + }); + this._dialog.add(this.buttonLayout, { + x_align: St.Align.MIDDLE, + y_align: St.Align.MIDDLE + }); + } + + makeInactive() { + if (this._eventId != 0) + this._parentActor.disconnect(this._eventId); + this._eventId = 0; + + this.buttonLayout.get_children().forEach(c => c.set_reactive(false)); + } + + _onDestroy() { + this.makeInactive(); + } + + _modalEventHandler(actor, event) { + if (event.type() == Clutter.EventType.KEY_PRESS) { + this._pressedKey = event.get_key_symbol(); + } else if (event.type() == Clutter.EventType.KEY_RELEASE) { + let pressedKey = this._pressedKey; + this._pressedKey = null; + + let symbol = event.get_key_symbol(); + if (symbol != pressedKey) + return Clutter.EVENT_PROPAGATE; + + let buttonInfo = this._buttonKeys[symbol]; + if (!buttonInfo) + return Clutter.EVENT_PROPAGATE; + + let { button, action } = buttonInfo; + + if (action && button.reactive) { + action(); + return Clutter.EVENT_STOP; + } + } + + return Clutter.EVENT_PROPAGATE; + } + + _setInitialKeyFocus(actor) { + if (this._initialKeyFocus) + this._initialKeyFocus.disconnect(this._initialKeyFocusDestroyId); + + this._initialKeyFocus = actor; + + this._initialKeyFocusDestroyId = actor.connect('destroy', () => { + this._initialKeyFocus = null; + this._initialKeyFocusDestroyId = 0; + }); + } + + get initialKeyFocus() { + return this._initialKeyFocus || this; + } + + addButton(buttonInfo) { + let { label, action, key } = buttonInfo; + let isDefault = buttonInfo['default']; + let isDestructive = buttonInfo['destructive_action']; + let keys; + + if (key) + keys = [key]; + else if (isDefault) + keys = [Clutter.KEY_Return, Clutter.KEY_KP_Enter, Clutter.KEY_ISO_Enter]; + else + keys = []; + + let button = new St.Button({ + style_class: 'dialog-button', + important: true, + button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, + reactive: true, + can_focus: true, + x_expand: true, + y_expand: true, + label: label + }); + button.connect('clicked', () => action()); + + buttonInfo['button'] = button; + + if (isDefault) + button.add_style_pseudo_class('default'); + + if (isDestructive) + button.add_style_pseudo_class('destructive-action'); + + if (this._initialKeyFocus == null || isDefault) + this._setInitialKeyFocus(button); + + for (let i in keys) + this._buttonKeys[keys[i]] = buttonInfo; + + this.buttonLayout.add_actor(button); + + return button; + } + + clearButtons() { + this.buttonLayout.destroy_all_children(); + this._buttonKeys = {}; + } +}); + +var MessageDialogContent = GObject.registerClass({ + Properties: { + 'title': GObject.ParamSpec.string( + 'title', 'title', 'title', + GObject.ParamFlags.READWRITE | + GObject.ParamFlags.CONSTRUCT, + null), + 'description': GObject.ParamSpec.string( + 'description', 'description', 'description', + GObject.ParamFlags.READWRITE | + GObject.ParamFlags.CONSTRUCT, + null), + } +}, class MessageDialogContent extends St.BoxLayout { + _init(params) { + this._title = new St.Label({ style_class: 'message-dialog-title' }); + this._description = new St.Label({ style_class: 'message-dialog-description' }); + + this._description.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; + this._description.clutter_text.line_wrap = true; + + let defaultParams = { + style_class: 'message-dialog-content', + x_expand: true, + vertical: true, + }; + super._init(Object.assign(defaultParams, params)); + + this.connect('notify::size', this._updateTitleStyle.bind(this)); + this.connect('destroy', this._onDestroy.bind(this)); + + this.add_child(this._title); + this.add_child(this._description); + } + + _onDestroy() { + if (this._updateTitleStyleLater) { + Meta.later_remove(this._updateTitleStyleLater); + delete this._updateTitleStyleLater; + } + } + + get title() { + return this._title.text; + } + + get description() { + return this._description.text; + } + + _updateTitleStyle() { + if (!this._title.mapped) + return; + + this._title.ensure_style(); + const [, titleNatWidth] = this._title.get_preferred_width(-1); + + if (titleNatWidth > this.width) { + if (this._updateTitleStyleLater) + return; + + this._updateTitleStyleLater = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { + this._updateTitleStyleLater = 0; + this._title.add_style_class_name('leightweight'); + return GLib.SOURCE_REMOVE; + }); + } + + } + + set title(title) { + if (this._title.text === title) + return; + + _setLabel(this._title, title); + + this._title.remove_style_class_name('leightweight'); + this._updateTitleStyle(); + + this.notify('title'); + } + + set description(description) { + if (this._description.text === description) + return; + + _setLabel(this._description, description); + this.notify('description'); + } +}); diff --git a/js/ui/layout.js b/js/ui/layout.js index 32c8c61f66..dd6fb7eabe 100644 --- a/js/ui/layout.js +++ b/js/ui/layout.js @@ -34,6 +34,123 @@ function isPopupMetaWindow(actor) { } } +var MonitorConstraint = GObject.registerClass({ + Properties: { + 'primary': GObject.ParamSpec.boolean( + 'primary', 'Primary', 'Track primary monitor', + GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE, + false), + 'index': GObject.ParamSpec.int( + 'index', 'Monitor index', 'Track specific monitor', + GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE, + -1, 64, -1), + 'work-area': GObject.ParamSpec.boolean( + 'work-area', 'Work-area', 'Track monitor\'s work-area', + GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE, + false), + }, +}, class MonitorConstraint extends Clutter.Constraint { + _init(props) { + this._primary = false; + this._index = -1; + this._workArea = false; + + super._init(props); + } + + get primary() { + return this._primary; + } + + set primary(v) { + if (v) + this._index = -1; + this._primary = v; + if (this.actor) + this.actor.queue_relayout(); + this.notify('primary'); + } + + get index() { + return this._index; + } + + set index(v) { + this._primary = false; + this._index = v; + if (this.actor) + this.actor.queue_relayout(); + this.notify('index'); + } + + get workArea() { + return this._workArea; + } + + set workArea(v) { + if (v === this._workArea) + return; + this._workArea = v; + if (this.actor) + this.actor.queue_relayout(); + this.notify('work-area'); + } + + vfunc_set_actor(actor) { + if (actor) { + if (!this._monitorsChangedId) { + this._monitorsChangedId = + Main.layoutManager.connect('monitors-changed', () => { + this.actor.queue_relayout(); + }); + } + + if (!this._workareasChangedId) { + this._workareasChangedId = + global.display.connect('workareas-changed', () => { + if (this._workArea) + this.actor.queue_relayout(); + }); + } + } else { + if (this._monitorsChangedId) + Main.layoutManager.disconnect(this._monitorsChangedId); + this._monitorsChangedId = 0; + + if (this._workareasChangedId) + global.display.disconnect(this._workareasChangedId); + this._workareasChangedId = 0; + } + + super.vfunc_set_actor(actor); + } + + vfunc_update_allocation(actor, actorBox) { + if (!this._primary && this._index < 0) + return; + + if (!Main.layoutManager.primaryMonitor) + return; + + let index; + if (this._primary) + index = Main.layoutManager.primaryIndex; + else + index = Math.min(this._index, Main.layoutManager.monitors.length - 1); + + let rect; + if (this._workArea) { + let workspaceManager = global.workspace_manager; + let ws = workspaceManager.get_workspace_by_index(0); + rect = ws.get_work_area_for_monitor(index); + } else { + rect = Main.layoutManager.monitors[index]; + } + + actorBox.init_rect(rect.x, rect.y, rect.width, rect.height); + } +}); + function Monitor(index, geometry) { this._init(index, geometry); } diff --git a/js/ui/modalDialog.js b/js/ui/modalDialog.js index 9ac710ad12..d7cb637c5a 100644 --- a/js/ui/modalDialog.js +++ b/js/ui/modalDialog.js @@ -1,11 +1,11 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- const Clutter = imports.gi.Clutter; -const Lang = imports.lang; const St = imports.gi.St; const Atk = imports.gi.Atk; const Cinnamon = imports.gi.Cinnamon; const Signals = imports.signals; +const GObject = imports.gi.GObject; const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; const Pango = imports.gi.Pango; @@ -15,12 +15,12 @@ const Gdk = imports.gi.Gdk; const Params = imports.misc.params; const Util = imports.misc.util; +const Dialog = imports.ui.dialog; const Lightbox = imports.ui.lightbox; const Main = imports.ui.main; const Gettext = imports.gettext; -const FADE_IN_BUTTONS_TIME = 330; const FADE_OUT_DIALOG_TIME = 1000; var OPEN_AND_CLOSE_TIME = 100; @@ -48,11 +48,16 @@ var State = { * For simple usage such as displaying a message, or asking for confirmation, * the #ConfirmDialog and #NotifyDialog classes may be used instead. */ -function ModalDialog(params) { - this._init(params); -} - -ModalDialog.prototype = { +var ModalDialog = GObject.registerClass({ + Properties: { + 'state': GObject.ParamSpec.int('state', 'Dialog state', 'state', + GObject.ParamFlags.READABLE, + Math.min(...Object.values(State)), + Math.max(...Object.values(State)), + State.CLOSED) + }, + Signals: { 'opened': {}, 'closed': {} } +}, class ModalDialog extends St.Widget { /** * _init: * @params (JSON): parameters for the modal dialog. Options include @@ -60,83 +65,70 @@ ModalDialog.prototype = { * block Cinnamon input, and @styleClass, which is the style class the * modal dialog should use. */ - _init: function(params) { + _init(params) { + super._init({ + visible: false, + x: 0, + y: 0, + accessible_role: Atk.Role.DIALOG, + }); + params = Params.parse(params, { cinnamonReactive: false, styleClass: null }); - this.state = State.CLOSED; + this._state = State.CLOSED; this._hasModal = false; this._cinnamonReactive = params.cinnamonReactive; - this._group = new St.Widget({ visible: false, - x: 0, - y: 0, - accessible_role: Atk.Role.DIALOG }); - Main.uiGroup.add_actor(this._group); + Main.uiGroup.add_actor(this); let constraint = new Clutter.BindConstraint({ source: global.stage, coordinate: Clutter.BindCoordinate.POSITION | Clutter.BindCoordinate.SIZE }); - this._group.add_constraint(constraint); - - this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy)); - - this._actionKeys = {}; - this._group.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent)); + this.add_constraint(constraint); - this._backgroundBin = new St.Bin(); - this._group.add_actor(this._backgroundBin); + this.backgroundStack = new St.Widget({ layout_manager: new Clutter.BinLayout() }); + this._backgroundBin = new St.Bin({ + child: this.backgroundStack, + x_fill: true, + y_fill: true + }); + this.add_actor(this._backgroundBin); - this._dialogLayout = new St.BoxLayout({ style_class: 'modal-dialog', - vertical: true, - important: true }); - if (params.styleClass != null) { - this._dialogLayout.add_style_class_name(params.styleClass); - } + this.dialogLayout = new Dialog.Dialog(this.backgroundStack, params.styleClass); + this.contentLayout = this.dialogLayout.contentLayout; + this.buttonLayout = this.dialogLayout.buttonLayout; if (!this._cinnamonReactive) { - this._lightbox = new Lightbox.Lightbox(this._group, + this._lightbox = new Lightbox.Lightbox(this, { inhibitEvents: true, radialEffect: true }); this._lightbox.highlight(this._backgroundBin); - let stack = new Cinnamon.Stack(); - this._backgroundBin.child = stack; - - this._eventBlocker = new Clutter.Group({ reactive: true }); - stack.add_actor(this._eventBlocker); - stack.add_actor(this._dialogLayout); - } else { - this._backgroundBin.child = this._dialogLayout; + this._eventBlocker = new Clutter.Actor({ reactive: true }); + this.backgroundStack.add_actor(this._eventBlocker); } + global.focus_manager.add_group(this.dialogLayout); + this._initialKeyFocus = null; + this._initialKeyFocusDestroyId = 0; + this._savedKeyFocus = null; + } - this.contentLayout = new St.BoxLayout({ vertical: true }); - this._dialogLayout.add(this.contentLayout, - { x_fill: true, - y_fill: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.START }); + get state() { + return this._state; + } - this._buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box', - vertical: false }); - this._dialogLayout.add(this._buttonLayout, - { expand: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.END }); + _setState(state) { + if (this._state == state) + return; - global.focus_manager.add_group(this._dialogLayout); - this._initialKeyFocus = this._dialogLayout; - this._savedKeyFocus = null; - }, + this._state = state; + this.notify('state'); + } - /** - * destroy: - * - * Destroys the modal dialog - */ - destroy: function() { - this._group.destroy(); - }, + clearButtons() { + this.dialogLayout.clearButtons(); + } /** * setButtons: @@ -152,145 +144,73 @@ ModalDialog.prototype = { * Optional arguments include @focused, which determines whether the button * is initially focused, and @key, which is a keybinding associated with * the button press such that pressing the keybinding will have the same - * effect as clicking the button. + * effect as clicking the button. Other arguments include @default + * and @destructive_action which add additional styling. * * An example usage is * ``` * dialog.setButtons([ * { * label: _("Cancel"), - * action: Lang.bind(this, this.callback), + * action: this.callback.bind(this), * key: Clutter.KEY_Escape * }, * { * label: _("OK"), - * action: Lang.bind(this, this.destroy), - * key: Clutter.KEY_Return + * action: this.destroy.bind(this), + * key: Clutter.KEY_Return, + * default: true * } * ]); * ``` */ - setButtons: function(buttons) { - let hadChildren = this._buttonLayout.get_n_children() > 0; + setButtons(buttons) { + this.clearButtons(); - this._buttonLayout.destroy_all_children(); - this._actionKeys = {}; - let focusSetExplicitly = false; - - for (let i = 0; i < buttons.length; i ++) { - let buttonInfo = buttons[i]; - if (!buttonInfo.focused) { - buttonInfo.focused = false; - } - let label = buttonInfo['label']; - let action = buttonInfo['action']; - let key = buttonInfo['key']; - let wantsfocus = buttonInfo['focused'] === true; - let nofocus = buttonInfo['focused'] === false; - buttonInfo.button = new St.Button({ style_class: 'modal-dialog-button', - reactive: true, - can_focus: true, - label: label }); - - let x_alignment; - if (buttons.length == 1) - x_alignment = St.Align.END; - else if (i == 0) - x_alignment = St.Align.START; - else if (i == buttons.length - 1) - x_alignment = St.Align.END; - else - x_alignment = St.Align.MIDDLE; - - if (wantsfocus) { - this._initialKeyFocus = buttonInfo.button; - focusSetExplicitly = true; - } - - if (!focusSetExplicitly && !nofocus && (this._initialKeyFocus == this._dialogLayout || - this._buttonLayout.contains(this._initialKeyFocus))) - { - this._initialKeyFocus = buttonInfo.button; - } - this._buttonLayout.add(buttonInfo.button, - { expand: true, - x_fill: false, - y_fill: false, - x_align: x_alignment, - y_align: St.Align.MIDDLE }); - - buttonInfo.button.connect('clicked', action); - - if (key) - this._actionKeys[key] = action; - } - - // Fade in buttons if there weren't any before - if (!hadChildren && buttons.length > 0) { - this._buttonLayout.opacity = 0; - this._buttonLayout.ease({ - opacity: 255, - duration: FADE_IN_BUTTONS_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - this.emit('buttons-set'); - } - }); - } else { - this.emit('buttons-set'); + for (let buttonInfo of buttons) { + this.addButton(buttonInfo); } + } - }, - - _onKeyPressEvent: function(object, keyPressEvent) { - let modifiers = Cinnamon.get_event_state(keyPressEvent); - let ctrlAltMask = Clutter.ModifierType.CONTROL_MASK | Clutter.ModifierType.MOD1_MASK; - let symbol = keyPressEvent.get_key_symbol(); - - let action = this._actionKeys[symbol]; - - if (action) { - action(); - return; - } - - if (symbol === Clutter.KEY_Escape && !(modifiers & ctrlAltMask)) { - this.close(); - return; - } - }, - - _onGroupDestroy: function() { - this.emit('destroy'); - }, + addButton(buttonInfo) { + return this.dialogLayout.addButton(buttonInfo); + } - _fadeOpen: function() { + _fadeOpen() { let monitor = Main.layoutManager.currentMonitor; this._backgroundBin.set_position(monitor.x, monitor.y); this._backgroundBin.set_size(monitor.width, monitor.height); - this.state = State.OPENING; + this._setState(State.OPENING); - this._dialogLayout.opacity = 255; + this.dialogLayout.opacity = 255; if (this._lightbox) this._lightbox.show(); - this._group.opacity = 0; - this._group.show(); - this._group.ease({ + this.opacity = 0; + this.show(); + this.ease({ opacity: 255, duration: OPEN_AND_CLOSE_TIME, mode: Clutter.AnimationMode.EASE_OUT_QUAD, onComplete: () => { - this.state = State.OPENED; + this._setState(State.OPENED); this.emit('opened'); } }); - }, + } + + setInitialKeyFocus(actor) { + if (this._initialKeyFocusDestroyId) + this._initialKeyFocus.disconnect(this._initialKeyFocusDestroyId); - setInitialKeyFocus: function(actor) { this._initialKeyFocus = actor; - }, + + this._initialKeyFocusDestroyId = actor.connect('destroy', () => { + this._initialKeyFocus = null; + this._initialKeyFocusDestroyId = 0; + }); + } /** * open: @@ -299,7 +219,7 @@ ModalDialog.prototype = { * * Opens and displays the modal dialog. */ - open: function(timestamp) { + open(timestamp) { if (this.state == State.OPENED || this.state == State.OPENING) return true; @@ -308,7 +228,7 @@ ModalDialog.prototype = { this._fadeOpen(); return true; - }, + } /** * close: @@ -317,24 +237,25 @@ ModalDialog.prototype = { * * Closes the modal dialog. */ - close: function(timestamp) { + close(timestamp) { if (this.state == State.CLOSED || this.state == State.CLOSING) return; - this.state = State.CLOSING; + this._setState(State.CLOSING); this.popModal(timestamp); this._savedKeyFocus = null; - this._group.ease({ + this.ease({ opacity: 0, duration: OPEN_AND_CLOSE_TIME, mode: Clutter.AnimationMode.EASE_OUT_QUAD, onComplete: () => { - this.state = State.CLOSED; - this._group.hide(); + this._setState(State.CLOSED); + this.hide(); + this.emit('closed'); } }); - }, + } /** * popModal: @@ -345,16 +266,16 @@ ModalDialog.prototype = { * dialog insensitive as well, so it needs to be followed shortly * by either a %close() or a %pushModal() */ - popModal: function(timestamp) { + popModal(timestamp) { if (!this._hasModal) return; let focus = global.stage.key_focus; - if (focus && this._group.contains(focus)) + if (focus && this.contains(focus)) this._savedKeyFocus = focus; else this._savedKeyFocus = null; - Main.popModal(this._group, timestamp); + Main.popModal(this, timestamp); if (!Meta.is_wayland_compositor()) { Gdk.Display.get_default().sync(); @@ -364,7 +285,7 @@ ModalDialog.prototype = { if (!this._cinnamonReactive) this._eventBlocker.raise_top(); - }, + } /** * pushModal: @@ -374,23 +295,25 @@ ModalDialog.prototype = { * Pushes the modal to the modal stack so that it grabs the required * inputs. */ - pushModal: function (timestamp) { + pushModal(timestamp) { if (this._hasModal) return true; - if (!Main.pushModal(this._group, timestamp)) + if (!Main.pushModal(this, timestamp)) return false; this._hasModal = true; if (this._savedKeyFocus) { this._savedKeyFocus.grab_key_focus(); this._savedKeyFocus = null; - } else - this._initialKeyFocus.grab_key_focus(); + } else { + let focus = this._initialKeyFocus || this.dialogLayout.initialKeyFocus; + focus.grab_key_focus(); + } if (!this._cinnamonReactive) this._eventBlocker.lower_bottom(); return true; - }, + } /** * _fadeOutDialog: @@ -410,7 +333,7 @@ ModalDialog.prototype = { * immediately, but the lightbox should remain until the logout is * complete. */ - _fadeOutDialog: function(timestamp) { + _fadeOutDialog(timestamp) { if (this.state == State.CLOSED || this.state == State.CLOSING) return; @@ -418,17 +341,16 @@ ModalDialog.prototype = { return; this.popModal(timestamp); - this._dialogLayout.ease({ + this.dialogLayout.ease({ opacity: 0, duration: FADE_OUT_DIALOG_TIME, mode: Clutter.AnimationMode.EASE_OUT_QUAD, onComplete: () => { - this.state = State.FADED_OUT + this._setState(State.FADED_OUT); } }); } -}; -Signals.addSignalMethods(ModalDialog.prototype); +}); /** * #ConfirmDialog @@ -440,43 +362,41 @@ Signals.addSignalMethods(ModalDialog.prototype); * * Inherits: ModalDialog.ModalDialog */ -function ConfirmDialog(label, callback){ - this._init(label, callback); -} - -ConfirmDialog.prototype = { - __proto__: ModalDialog.prototype, +var ConfirmDialog = GObject.registerClass( +class ConfirmDialog extends ModalDialog { /** * _init: - * @label (string): label to display on the confirm dialog + * @description (string): label to display on the confirm dialog * @callback (function): function to call when user clicks "yes" * * Constructor function. */ - _init: function(label, callback){ - ModalDialog.prototype._init.call(this); - this.contentLayout.add(new St.Label({ text: _("Confirm"), - style_class: 'confirm-dialog-title', - important: true })); - this.contentLayout.add(new St.Label({text: label})); + _init(description, callback) { + super._init(); + + let title = _("Confirm"); + + let content = new Dialog.MessageDialogContent({ title, description }); + this.contentLayout.add_child(content); this.callback = callback; this.setButtons([ { label: _("No"), - action: Lang.bind(this, this.destroy) + action: this.destroy.bind(this) }, { label: _("Yes"), - action: Lang.bind(this, function(){ + action: () => { this.destroy(); this.callback(); - }) + }, + destructive_action: true } ]); - }, -}; + } +}); /** * #NotifyDialog @@ -488,31 +408,27 @@ ConfirmDialog.prototype = { * * Inherits: ModalDialog.ModalDialog */ -function NotifyDialog(label){ - this._init(label); -} - -NotifyDialog.prototype = { - __proto__: ModalDialog.prototype, +var NotifyDialog = GObject.registerClass( +class NotifyDialog extends ModalDialog { /** * _init: - * @label (string): label to display on the notify dialog + * @description (string): label to display on the notify dialog * * Constructor function. */ - _init: function(label){ - ModalDialog.prototype._init.call(this); + _init(description) { + super._init(); this.contentLayout.add(new St.Label({text: label})); this.setButtons([ { label: _("OK"), - action: Lang.bind(this, this.destroy) + action: this.destroy.bind(this) } ]); - }, -}; + } +}); /** * #InfoOSD @@ -528,11 +444,7 @@ NotifyDialog.prototype = { * destroying it after usage (via the %destroy function), or hiding it with * %hide for later reuse. */ -function InfoOSD(text) { - this._init(text); -} - -InfoOSD.prototype = { +var InfoOSD = class { /** * _init: @@ -541,14 +453,22 @@ InfoOSD.prototype = { * Constructor function. Creates an OSD and adds it to the chrome. Adds a * label with text @text if specified. */ - _init: function(text) { - this.actor = new St.BoxLayout({vertical: true, style_class: "info-osd", important: true}); + constructor(text) { + this.actor = new St.BoxLayout({ + vertical: true, + style_class: "info-osd", + important: true + }); + if (text) { let label = new St.Label({text: text}); this.actor.add(label); } - Main.layoutManager.addChrome(this.actor, {visibleInFullscreen: false, affectsInputRegion: false}); - }, + Main.layoutManager.addChrome(this.actor, { + visibleInFullscreen: false, + affectsInputRegion: false + }); + } /** * show: @@ -558,7 +478,7 @@ InfoOSD.prototype = { * Shows the OSD at the center of monitor @monitorIndex. Shows at the * primary monitor if not specified. */ - show: function(monitorIndex) { + show(monitorIndex) { let monitor; if (!monitorIndex) { @@ -576,26 +496,26 @@ InfoOSD.prototype = { this.actor.set_position(x, y); this.actor.opacity = 255; - }, + } /** * hide: * * Hides the OSD. */ - hide: function() { + hide() { this.actor.hide(); - }, + } /** * destroy: * * Destroys the OSD */ - destroy: function() { + destroy() { this.hide(); Main.layoutManager.removeChrome(this.actor); - }, + } /** * addText: @@ -604,10 +524,10 @@ InfoOSD.prototype = { * * Adds a text label displaying @text to the OSD */ - addText: function(text, params) { + addText(text, params) { let label = new St.Label({text: text}); this.actor.add(label, params); - }, + } /** * addActor: @@ -616,7 +536,7 @@ InfoOSD.prototype = { * * Adds the actor @actor to the OSD */ - addActor: function(actor, params) { + addActor(actor, params) { this.actor.add(actor, params); } -} +}; diff --git a/js/ui/osdWindow.js b/js/ui/osdWindow.js index 7c234a09cc..82491c525e 100644 --- a/js/ui/osdWindow.js +++ b/js/ui/osdWindow.js @@ -1,19 +1,20 @@ -const St = imports.gi.St; +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + const Clutter = imports.gi.Clutter; -const Lang = imports.lang; -const Main = imports.ui.main; -const Mainloop = imports.mainloop; -const Tweener = imports.ui.tweener; -const Gio = imports.gi.Gio; const Gdk = imports.gi.Gdk; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; const Meta = imports.gi.Meta; -const Cinnamon = imports.gi.Cinnamon; +const St = imports.gi.St; -const LEVEL_ANIMATION_TIME = 0.1; -const FADE_TIME = 0.1; -const HIDE_TIMEOUT = 1500; +const BarLevel = imports.ui.barLevel; +const Layout = imports.ui.layout; +const Main = imports.ui.main; -const OSD_SIZE = 110; +const LEVEL_ANIMATION_TIME = 100; +const FADE_TIME = 100; +const HIDE_TIMEOUT = 1500; function convertGdkIndex(monitorIndex) { let screen = Gdk.Screen.get_default(); @@ -30,279 +31,187 @@ function convertGdkIndex(monitorIndex) { return monitorIndex; }; -function LevelBar() { - this._init(); -} - -LevelBar.prototype = { - _init: function() { - this._level = 0; - - this.initial = true; - - this.actor = new Cinnamon.GenericContainer({ style_class: 'level', - x_align: St.Align.START, - important: true }); - this.actor.connect("allocate", this._allocate_bar.bind(this)); - - this._bar = new St.Widget({ style_class: 'level-bar', - important: true }); - this.actor.add_actor(this._bar); - }, - - _allocate_bar: function(actor, box, flags) { - let level_box = box.copy(); - - let new_width = (level_box.x2 - level_box.x1) * (this._level / 100); - level_box.x2 = Math.min((level_box.x1 + new_width), box.x2); - this._bar.allocate(level_box, flags); - }, - - get level() { - return this._level; - }, - - set level(value) { - this._level = Math.max(0, Math.min(value, 100)); - - let newWidth = this.actor.width * (this._level / 100); - - if (newWidth != this._bar.width) { - this._bar.width = newWidth; - } - - this.actor.queue_redraw(); - }, - - setLevelBarHeight: function(sizeMultiplier) { - let themeNode = this.actor.get_theme_node(); - let height = themeNode.get_height(); - let newHeight = Math.floor(height * sizeMultiplier); - this.actor.set_height(newHeight); - } -}; - -function OsdWindow(monitorIndex, size) { - this._init(monitorIndex, size); -} - -OsdWindow.prototype = { - _init: function(monitorIndex, size) { - this._popupSize = 0; - this._osdBaseSize = null; +var OsdWindow = GObject.registerClass( +class OsdWindow extends Clutter.Actor { + _init(monitorIndex) { + super._init({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.END, + }); this._monitorIndex = monitorIndex; + let constraint = new Layout.MonitorConstraint({ index: monitorIndex }); + this.add_constraint(constraint); + + this._hbox = new St.BoxLayout({ + style_class: 'media-keys-osd', + important: true, + x_align: Clutter.ActorAlign.CENTER, + }); + this.add_actor(this._hbox); - this.actor = new St.BoxLayout({ style_class: 'osd-window', - vertical: true, - important: true }); + this._icon = new St.Icon({ y_expand: true }); + this._hbox.add_child(this._icon); - this._icon = new St.Icon(); - this.actor.add(this._icon, { expand: true }); + this._vbox = new St.BoxLayout({ + vertical: true, + y_align: Clutter.ActorAlign.CENTER, + }); + this._hbox.add_child(this._vbox); - this._level = new LevelBar(); - this.actor.add(this._level.actor); - this._label = new St.Label(); - this._label.style = 'font-size: 1.2em; text-align: center;' - this.actor.add(this._label); + this._vbox.add_child(this._label); + + this._level = new BarLevel.BarLevel({ + style_class: 'level', + value: 0, + }); + this._vbox.add_child(this._level); this._hideTimeoutId = 0; this._reset(); + Main.uiGroup.add_child(this); + } - Main.uiGroup.add_child(this.actor); + setIcon(icon) { + this._icon.gicon = icon; + } - this._sizeAndPosition(size); - }, + setLabel(label) { + this._label.visible = label != null; + if (this._label.visible) + this._label.text = label; + } - setIcon: function(icon) { - this._icon.gicon = icon; - }, - - setLevel: function(level) { - if (level != undefined) { - this._label.set_text(String(level) + " %"); - this._label.visible = this._level.actor.visible = true; - - if (this.actor.visible) - Tweener.addTween(this._level, - { level: level, - time: LEVEL_ANIMATION_TIME, - transition: 'easeOutQuad' }); + setLevel(value) { + this._level.visible = value != null; + if (this._level.visible) { + value = value / 100; + if (this.visible) + this._level.ease_property('value', value, { + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + duration: LEVEL_ANIMATION_TIME, + }); else - this._level.level = level; - } else { - this._label.set_text(""); - this._label.visible = this._level.actor.visible = false; + this._level.value = value; } - }, + } - show: function() { - if (this._osdBaseSize == null) - return; + setMaxLevel(maxLevel = 1) { + this._level.maximum_value = maxLevel; + } + show() { if (!this._icon.gicon) return; - if (!this.actor.visible) { + if (!this.visible) { Meta.disable_unredirect_for_display(global.display); - this._level.setLevelBarHeight(this._sizeMultiplier); - this.actor.show(); - this.actor.opacity = 0; - this.actor.raise_top(); - - Tweener.addTween(this.actor, - { opacity: 255, - time: FADE_TIME, - transition: 'easeOutQuad' }); + super.show(); + this.opacity = 0; + this.get_parent().set_child_above_sibling(this, null); + + this.ease({ + opacity: 255, + duration: FADE_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); } if (this._hideTimeoutId) - Mainloop.source_remove(this._hideTimeoutId); - this._hideTimeoutId = Mainloop.timeout_add(HIDE_TIMEOUT, Lang.bind(this, this._hide)); - }, + GLib.source_remove(this._hideTimeoutId); + this._hideTimeoutId = GLib.timeout_add( + GLib.PRIORITY_DEFAULT, HIDE_TIMEOUT, this._hide.bind(this)); + GLib.Source.set_name_by_id(this._hideTimeoutId, '[cinnamon] this._hide'); + } - cancel: function() { + cancel() { if (!this._hideTimeoutId) return; - Mainloop.source_remove(this._hideTimeoutId); + GLib.source_remove(this._hideTimeoutId); this._hide(); - }, + } - _hide: function() { + _hide() { this._hideTimeoutId = 0; - Tweener.addTween(this.actor, - { opacity: 0, - time: FADE_TIME, - transition: 'easeOutQuad', - onComplete: Lang.bind(this, function() { - this._reset(); - Meta.enable_unredirect_for_display(global.display); - }) - }); - }, - - _reset: function() { - this.actor.hide(); - }, - - destroy: function() { - Main.uiGroup.remove_child(this.actor); - this.actor.destroy(); - }, - - _sizeAndPosition: function(sizeFromSettings) { - switch (sizeFromSettings) { - case "disabled": - this._osdBaseSize = null; - break; - case "small": - this._sizeMultiplier = 0.7; - this._osdBaseSize = Math.floor(OSD_SIZE * this._sizeMultiplier); - break; - case "large": - this._sizeMultiplier = 1.0; - this._osdBaseSize = OSD_SIZE; - break; - default: - this._sizeMultiplier = 0.85; - this._osdBaseSize = Math.floor(OSD_SIZE * this._sizeMultiplier); - } - - let monitor = Main.layoutManager.monitors[this._monitorIndex]; - if (monitor) { - let scaleW = monitor.width / 640.0; - let scaleH = monitor.height / 480.0; - let scale = Math.min(scaleW, scaleH); - this._popupSize = this._osdBaseSize * Math.max(1, scale); - - let scaleFactor = global.ui_scale; - this._icon.icon_size = this._popupSize / (2 * scaleFactor); - this.actor.set_size(this._popupSize, this._popupSize); - this.actor.translation_y = (monitor.height + monitor.y) - (this._popupSize + (50 * scaleFactor)); - this.actor.translation_x = ((monitor.width / 2) + monitor.x) - (this._popupSize / 2); - - if (monitor.height < 900 && ["small", "medium"].includes(sizeFromSettings)) { - let spacing = this.actor.get_theme_node().get_length ("spacing"); - let multiplier = 1.0; - - if (sizeFromSettings === "small") { - this._label.style = 'font-size: 0.8em; text-align: center;' - multiplier = 0.6; - } else - if (sizeFromSettings === "medium") { - this._label.style = 'font-size: 1.0em; text-align: center;' - multiplier = 0.8; - } - - this.actor.style = `spacing: ${Math.floor(spacing * multiplier)}px;`; - } else { - this._label.style = 'font-size: 1.2em; text-align: center;' - this.actor.style = null; - } - } + this.ease({ + opacity: 0, + duration: FADE_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => { + this._reset(); + Meta.enable_unredirect_for_display(global.display); + }, + }); + return GLib.SOURCE_REMOVE; } -}; -function OsdWindowManager() { - this._init(); -} + _reset() { + super.hide(); + this.setLabel(null); + this.setMaxLevel(null); + this.setLevel(null); + } +}); -OsdWindowManager.prototype = { - _init: function() { +var OsdWindowManager = class { + constructor() { this._osdWindows = []; - Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._layoutChanged)); + Main.layoutManager.connect('monitors-changed', this._layoutChanged.bind(this)); this._osdSettings = new Gio.Settings({ schema_id: "org.cinnamon" }); - this._osdSettings.connect("changed::show-media-keys-osd", Lang.bind(this, this._layoutChanged)); + this._osdSettings.connect("changed::show-media-keys-osd", this._layoutChanged.bind(this)); this._layoutChanged(); - }, + } - _layoutChanged: function() { + _layoutChanged() { this._osdWindows.forEach((osd) => { osd.destroy(); }) this._osdWindows = []; - let size = this._osdSettings.get_string("show-media-keys-osd"); - if (size === "disabled") + if (!this._osdSettings.get_boolean("show-media-keys-osd")) return; for (let i = 0; i < Main.layoutManager.monitors.length; i++) { - if (this._osdWindows[i] == undefined) - this._osdWindows[i] = new OsdWindow(i, size); + if (this._osdWindows[i] === undefined) + this._osdWindows[i] = new OsdWindow(i); } - }, + } - _showOsdWindow: function(monitorIndex, icon, level) { + _showOsdWindow(monitorIndex, icon, label, level) { this._osdWindows[monitorIndex].setIcon(icon); + this._osdWindows[monitorIndex].setLabel(label); + this._osdWindows[monitorIndex].setMaxLevel(1); this._osdWindows[monitorIndex].setLevel(level); this._osdWindows[monitorIndex].show(); - }, + } - show: function(monitorIndex, icon, level, convertIndex) { + show(monitorIndex, icon, label, level, convertIndex) { if (this._osdWindows.length === 0) return; - if (monitorIndex != -1) { + if (monitorIndex !== -1) { if (convertIndex) monitorIndex = convertGdkIndex(monitorIndex); for (let i = 0; i < this._osdWindows.length; i++) { - if (i == monitorIndex) - this._showOsdWindow(i, icon, level); + if (i === monitorIndex) + this._showOsdWindow(i, icon, label, level); else this._osdWindows[i].cancel(); } } else { for (let i = 0; i < this._osdWindows.length; i++) - this._showOsdWindow(i, icon, level); + this._showOsdWindow(i, icon, label, level); } - }, + } - hideAll: function() { + hideAll() { if (this._osdWindows.length === 0) return; diff --git a/js/ui/polkitAuthenticationAgent.js b/js/ui/polkitAuthenticationAgent.js index 5f0b55c387..c1c5cf4d63 100644 --- a/js/ui/polkitAuthenticationAgent.js +++ b/js/ui/polkitAuthenticationAgent.js @@ -20,7 +20,6 @@ * Author: David Zeuthen */ -const Lang = imports.lang; const Signals = imports.signals; const Cinnamon = imports.gi.Cinnamon; const AccountsService = imports.gi.AccountsService; @@ -28,53 +27,40 @@ const Clutter = imports.gi.Clutter; const St = imports.gi.St; const Pango = imports.gi.Pango; const Gio = imports.gi.Gio; +const GObject = imports.gi.GObject; +const GLib = imports.gi.GLib; const Mainloop = imports.mainloop; const Polkit = imports.gi.Polkit; const PolkitAgent = imports.gi.PolkitAgent; +const Dialog = imports.ui.dialog; const ModalDialog = imports.ui.modalDialog; const CinnamonEntry = imports.ui.cinnamonEntry; const UserWidget = imports.ui.userWidget; +const Util = imports.misc.util; const DIALOG_ICON_SIZE = 64; +const DELAYED_RESET_TIMEOUT = 200; -function AuthenticationDialog(actionId, message, cookie, userNames) { - this._init(actionId, message, cookie, userNames); -} - -AuthenticationDialog.prototype = { - __proto__: ModalDialog.ModalDialog.prototype, - - _init: function(actionId, message, cookie, userNames) { - ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'polkit-dialog' }); +var AuthenticationDialog = GObject.registerClass({ + Signals: { 'done': { param_types: [GObject.TYPE_BOOLEAN] } } +}, class AuthenticationDialog extends ModalDialog.ModalDialog { + _init(actionId, description, cookie, userNames) { + super._init({ styleClass: 'prompt-dialog' }); this.actionId = actionId; - this.message = message; + this.message = description; this.userNames = userNames; this._wasDismissed = false; - this._completed = false; - let mainContentBox = new St.BoxLayout({ style_class: 'polkit-dialog-main-layout', - vertical: true }); - this.contentLayout.add(mainContentBox, - { x_fill: true, - y_fill: true }); + this.connect('closed', this._onDialogClosed.bind(this)); - this._subjectLabel = new St.Label({ style_class: 'polkit-dialog-headline', - text: _("Authentication Required") }); + let title = _("Authentication Required"); - mainContentBox.add(this._subjectLabel, - { y_fill: false, - y_align: St.Align.MIDDLE }); + let headerContent = new Dialog.MessageDialogContent({ title, description }); + this.contentLayout.add_child(headerContent); - this._descriptionLabel = new St.Label({ style_class: 'polkit-dialog-description', - text: message }); - this._descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; - this._descriptionLabel.clutter_text.line_wrap = true; - - mainContentBox.add(this._descriptionLabel, - { y_fill: true, - y_align: St.Align.START }); + let bodyContent = new Dialog.MessageDialogContent(); if (userNames.length > 1) { log('polkitAuthenticationAgent: Received ' + userNames.length + @@ -82,113 +68,137 @@ AuthenticationDialog.prototype = { 'considering the first one.'); } - let userName = userNames[0]; + let userName = GLib.get_user_name(); + if (!userNames.includes(userName)) + userName = 'root'; + if (!userNames.includes(userName)) + userName = userNames[0]; this._user = AccountsService.UserManager.get_default().get_user(userName); - let userRealName = this._user.get_real_name() - this._userLoadedId = this._user.connect('notify::is_loaded', - Lang.bind(this, this._onUserChanged)); - this._userChangedId = this._user.connect('changed', - Lang.bind(this, this._onUserChanged)); - - // Special case 'root' - let userIsRoot = false; - if (userName == 'root') { - userIsRoot = true; - userRealName = _("Administrator"); - } - - if (userIsRoot) { - let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-root-label', - text: userRealName })); - mainContentBox.add(userLabel); - } else { - let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout', - vertical: true }); - mainContentBox.add(userBox); - this._userIcon = new UserWidget.Avatar(this._user, { iconSize: DIALOG_ICON_SIZE }); - this._userIcon.hide(); - userBox.add(this._userIcon, - { x_fill: false, - y_fill: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.START }); - let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-label', - text: userRealName })); - userBox.add(userLabel, - { x_fill: false, - y_fill: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.START }); - } - this._onUserChanged(); - - this._passwordBox = new St.BoxLayout({ vertical: false }); - mainContentBox.add(this._passwordBox); - this._passwordLabel = new St.Label(({ style_class: 'polkit-dialog-password-label' })); - this._passwordBox.add(this._passwordLabel, - { y_align: St.Align.MIDDLE }); - this._passwordEntry = new St.Entry({ style_class: 'polkit-dialog-password-entry', - text: "", - can_focus: true}); + let userBox = new St.BoxLayout({ + style_class: 'polkit-dialog-user-layout', + important: true, + vertical: true, + }); + bodyContent.add_child(userBox); + + this._userAvatar = new UserWidget.Avatar(this._user, { + iconSize: DIALOG_ICON_SIZE, + }); + this._userAvatar.x_align = Clutter.ActorAlign.CENTER; + userBox.add(this._userAvatar, { x_fill: false }); + + this._userLabel = new St.Label({ + style_class: userName === 'root' + ? 'polkit-dialog-user-root-label' + : 'polkit-dialog-user-label', + }); + + if (userName === 'root') + this._userLabel.text = _('Administrator'); + + userBox.add_child(this._userLabel); + + let passwordBox = new St.BoxLayout({ + style_class: 'prompt-dialog-password-layout', + vertical: true, + }); + + this._passwordEntry = new St.Entry({ + style_class: 'prompt-dialog-password-entry', + text: "", + can_focus: true, + visible: false, + x_align: Clutter.ActorAlign.CENTER, + }); CinnamonEntry.addContextMenu(this._passwordEntry, { isPassword: true }); - this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivate)); - this._passwordBox.add(this._passwordEntry, - { expand: true, - y_align: St.Align.START }); - this.setInitialKeyFocus(this._passwordEntry); - this._passwordBox.hide(); - - this._errorMessageLabel = new St.Label({ style_class: 'polkit-dialog-error-label' }); + this._passwordEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this)); + this._passwordEntry.bind_property('reactive', + this._passwordEntry.clutter_text, 'editable', + GObject.BindingFlags.SYNC_CREATE); + passwordBox.add_child(this._passwordEntry); + + let warningBox = new St.BoxLayout({ vertical: true }); + + this._errorMessageLabel = new St.Label({ + style_class: 'prompt-dialog-error-label', + visible: false, + }); this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; this._errorMessageLabel.clutter_text.line_wrap = true; - mainContentBox.add(this._errorMessageLabel); - this._errorMessageLabel.hide(); - this._infoMessageLabel = new St.Label({ style_class: 'polkit-dialog-info-label' }); + warningBox.add_child(this._errorMessageLabel); + + this._infoMessageLabel = new St.Label({ + style_class: 'prompt-dialog-info-label', + visible: false, + }); this._infoMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; this._infoMessageLabel.clutter_text.line_wrap = true; - mainContentBox.add(this._infoMessageLabel); - this._infoMessageLabel.hide(); + + warningBox.add_child(this._infoMessageLabel); /* text is intentionally non-blank otherwise the height is not the same as for * infoMessage and errorMessageLabel - but it is still invisible because * cinnamon.css sets the color to be transparent */ - this._nullMessageLabel = new St.Label({ style_class: 'polkit-dialog-null-label', - text: 'abc'}); + this._nullMessageLabel = new St.Label({ style_class: 'prompt-dialog-null-label' }); this._nullMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; this._nullMessageLabel.clutter_text.line_wrap = true; - mainContentBox.add(this._nullMessageLabel); - this._nullMessageLabel.show(); - this.setButtons([{ label: _("Cancel"), - action: Lang.bind(this, this.cancel), - key: Clutter.Escape - }, - { label: _("Authenticate"), - action: Lang.bind(this, this._onAuthenticateButtonPressed) - }]); + warningBox.add_child(this._nullMessageLabel); + + passwordBox.add_child(warningBox); + bodyContent.add_child(passwordBox); + + this._cancelButton = this.addButton({ + label: _("Cancel"), + action: this.cancel.bind(this), + key: Clutter.Escape + }); + this._okButton = this.addButton({ + label: _("Authenticate"), + action: this._onAuthenticateButtonPressed.bind(this), + reactive: false, + default: true + }); + this._okButton.bind_property('reactive', + this._okButton, 'can-focus', + GObject.BindingFlags.SYNC_CREATE); + + this._passwordEntry.clutter_text.connect('text-changed', text => { + this._okButton.reactive = text.get_text().length > 0; + }); + + this.contentLayout.add_child(bodyContent); this._doneEmitted = false; this._identityToAuth = Polkit.UnixUser.new_for_name(userName); this._cookie = cookie; - this._session = new PolkitAgent.Session({ identity: this._identityToAuth, - cookie: this._cookie }); - this._session.connect('completed', Lang.bind(this, this._onSessionCompleted)); - this._session.connect('request', Lang.bind(this, this._onSessionRequest)); - this._session.connect('show-error', Lang.bind(this, this._onSessionShowError)); - this._session.connect('show-info', Lang.bind(this, this._onSessionShowInfo)); - }, + this._userLoadedId = this._user.connect('notify::is-loaded', + this._onUserChanged.bind(this)); + this._userChangedId = this._user.connect('changed', + this._onUserChanged.bind(this)); + this._onUserChanged(); + } - startAuthentication: function() { + performAuthentication() { + this._destroySession(DELAYED_RESET_TIMEOUT); + this._session = new PolkitAgent.Session({ + identity: this._identityToAuth, + cookie: this._cookie + }); + this._sessionCompletedId = this._session.connect('completed', this._onSessionCompleted.bind(this)); + this._sessionRequestId = this._session.connect('request', this._onSessionRequest.bind(this)); + this._sessionShowErrorId = this._session.connect('show-error', this._onSessionShowError.bind(this)); + this._sessionShowInfoId = this._session.connect('show-info', this._onSessionShowInfo.bind(this)); this._session.initiate(); - }, + } - _ensureOpen: function() { + _ensureOpen() { // NOTE: ModalDialog.open() is safe to call if the dialog is // already open - it just returns true without side-effects if (!this.open(global.get_current_time())) { @@ -206,38 +216,47 @@ AuthenticationDialog.prototype = { log('polkitAuthenticationAgent: Failed to show modal dialog.' + ' Dismissing authentication request for action-id ' + this.actionId + ' cookie ' + this._cookie); - this._emitDone(false, true); + this._emitDone(true); } - }, + } - _emitDone: function(keepVisible, dismissed) { + _emitDone(dismissed) { if (!this._doneEmitted) { this._doneEmitted = true; - this.emit('done', keepVisible, dismissed); + this.emit('done', dismissed); } - }, + } - _onEntryActivate: function() { + _onEntryActivate() { let response = this._passwordEntry.get_text(); + if (response.length === 0) + return; + + this._passwordEntry.reactive = false; + this._okButton.reactive = false; + this._session.response(response); // When the user responds, dismiss already shown info and // error texts (if any) this._errorMessageLabel.hide(); this._infoMessageLabel.hide(); this._nullMessageLabel.show(); - }, + } - _onAuthenticateButtonPressed: function() { + _onAuthenticateButtonPressed() { this._onEntryActivate(); - }, + } - _onSessionCompleted: function(session, gainedAuthorization) { - if (this._completed) + _onSessionCompleted(session, gainedAuthorization) { + if (this._completed || this._doneEmitted) return; this._completed = true; - if (!gainedAuthorization) { + if (gainedAuthorization) { + this._emitDone(false); + + } else { /* Unless we are showing an existing error message from the PAM * module (the PAM module could be reporting the authentication * error providing authentication-method specific information), @@ -252,89 +271,140 @@ AuthenticationDialog.prototype = { this._errorMessageLabel.show(); this._infoMessageLabel.hide(); this._nullMessageLabel.hide(); + + Util.wiggle(this._passwordEntry); } + + /* Try and authenticate again */ + this.performAuthentication(); + } + } + + _onSessionRequest(session, request, echoOn) { + if (this._sessionRequestTimeoutId) { + GLib.source_remove(this._sessionRequestTimeoutId); + this._sessionRequestTimeoutId = 0; } - this._emitDone(!gainedAuthorization, false); - }, - _onSessionRequest: function(session, request, echo_on) { // Cheap localization trick - if (request == 'Password:') - this._passwordLabel.set_text(_("Password:")); + if (request === 'Password:' || request === 'Password: ') + this._passwordEntry.hint_text = _("Password"); else - this._passwordLabel.set_text(request); + this._passwordEntry.hint_text = request; - if (echo_on) + if (echoOn) this._passwordEntry.clutter_text.set_password_char(''); else this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE - this._passwordBox.show(); + this._passwordEntry.show(); this._passwordEntry.set_text(''); - this._passwordEntry.grab_key_focus(); + this._passwordEntry.reactive = true; + this._okButton.reactive = false; + this._ensureOpen(); - }, + this._passwordEntry.grab_key_focus(); + } - _onSessionShowError: function(session, text) { + _onSessionShowError(session, text) { this._passwordEntry.set_text(''); this._errorMessageLabel.set_text(text); this._errorMessageLabel.show(); this._infoMessageLabel.hide(); this._nullMessageLabel.hide(); this._ensureOpen(); - }, + } - _onSessionShowInfo: function(session, text) { + _onSessionShowInfo(session, text) { this._passwordEntry.set_text(''); this._infoMessageLabel.set_text(text); this._infoMessageLabel.show(); this._errorMessageLabel.hide(); this._nullMessageLabel.hide(); this._ensureOpen(); - }, + } - destroySession: function() { + _destroySession(delay = 0) { if (this._session) { if (!this._completed) this._session.cancel(); + this._completed = false; + + this._session.disconnect(this._sessionCompletedId); + this._session.disconnect(this._sessionRequestId); + this._session.disconnect(this._sessionShowErrorId); + this._session.disconnect(this._sessionShowInfoId); this._session = null; } - }, - _onUserChanged: function() { - if (this._user.is_loaded) { - if (this._userIcon) { - this._userIcon.update(); - this._userIcon.show(); - } + if (this._sessionRequestTimeoutId) { + GLib.source_remove(this._sessionRequestTimeoutId); + this._sessionRequestTimeoutId = 0; } - }, - cancel: function() { + let resetDialog = () => { + if (this.state != ModalDialog.State.OPENED) + return; + + this._passwordEntry.hide(); + this._cancelButton.grab_key_focus(); + this._okButton.reactive = false; + }; + + if (delay) { + this._sessionRequestTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, delay, resetDialog); + GLib.Source.set_name_by_id(this._sessionRequestTimeoutId, '[cinnamon] this._sessionRequestTimeoutId'); + } else { + resetDialog(); + } + } + + _onUserChanged() { + if (!this._user.is_loaded) + return; + + let userName = this._user.get_user_name(); + let realName = this._user.get_real_name(); + + if (userName !== 'root') + this._userLabel.set_text(realName); + + this._userAvatar.update(); + } + + cancel() { this._wasDismissed = true; this.close(global.get_current_time()); - this._emitDone(false, true); - }, + this._emitDone(true); + } -}; -Signals.addSignalMethods(AuthenticationDialog.prototype); + _onDialogClosed() { + if (this._sessionRequestTimeoutId) + GLib.source_remove(this._sessionRequestTimeoutId); + this._sessionRequestTimeoutId = 0; -function AuthenticationAgent() { - this._init(); -} + if (this._user) { + this._user.disconnect(this._userLoadedId); + this._user.disconnect(this._userChangedId); + this._user = null; + } -AuthenticationAgent.prototype = { - _init: function() { + this._destroySession(); + } + +}); + +var AuthenticationAgent = class { + constructor() { this._native = new Cinnamon.PolkitAuthenticationAgent(); - this._native.connect('initiate', Lang.bind(this, this._onInitiate)); - this._native.connect('cancel', Lang.bind(this, this._onCancel)); + this._native.connect('initiate', this._onInitiate.bind(this)); + this._native.connect('cancel', this._onCancel.bind(this)); // TODO - maybe register probably should wait until later, especially at first login? this._native.register(); this._currentDialog = null; - this._isCompleting = false; - }, + } - _onInitiate: function(nativeAgent, actionId, message, iconName, cookie, userNames) { + _onInitiate(nativeAgent, actionId, message, iconName, cookie, userNames) { this._currentDialog = new AuthenticationDialog(actionId, message, cookie, userNames); // We actually don't want to open the dialog until we know for @@ -347,44 +417,23 @@ AuthenticationAgent.prototype = { // See https://bugzilla.gnome.org/show_bug.cgi?id=643062 for more // discussion. - this._currentDialog.connect('done', Lang.bind(this, this._onDialogDone)); - this._currentDialog.startAuthentication(); - }, + this._currentDialog.connect('done', this._onDialogDone.bind(this)); + this._currentDialog.performAuthentication(); + } - _onCancel: function(nativeAgent) { - this._completeRequest(false, false); - }, + _onCancel(nativeAgent) { + this._completeRequest(false); + } - _onDialogDone: function(dialog, keepVisible, dismissed) { - this._completeRequest(keepVisible, dismissed); - }, + _onDialogDone(dialog, dismissed) { + this._completeRequest(dismissed); + } - _reallyCompleteRequest: function(dismissed) { + _completeRequest(dismissed) { this._currentDialog.close(); - this._currentDialog.destroySession(); this._currentDialog = null; - this._isCompleting = false; - this._native.complete(dismissed) - }, - - _completeRequest: function(keepVisible, wasDismissed) { - if (this._isCompleting) - return; - - this._isCompleting = true; - - if (keepVisible) { - // Give the user 2 seconds to read 'Authentication Failure' before - // dismissing the dialog - Mainloop.timeout_add(2000, - Lang.bind(this, - function() { - this._reallyCompleteRequest(wasDismissed); - })); - } else { - this._reallyCompleteRequest(wasDismissed); - } + this._native.complete(dismissed); } } diff --git a/js/ui/runDialog.js b/js/ui/runDialog.js index 736f22b518..7da4d0cd0b 100644 --- a/js/ui/runDialog.js +++ b/js/ui/runDialog.js @@ -3,19 +3,18 @@ const Clutter = imports.gi.Clutter; const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; const Pango = imports.gi.Pango; -const Lang = imports.lang; const Mainloop = imports.mainloop; const Meta = imports.gi.Meta; const St = imports.gi.St; const Cinnamon = imports.gi.Cinnamon; -const Signals = imports.signals; const FileUtils = imports.misc.fileUtils; const Main = imports.ui.main; +const Dialog = imports.ui.dialog; const ModalDialog = imports.ui.modalDialog; const CinnamonEntry = imports.ui.cinnamonEntry; -const Tweener = imports.ui.tweener; const Util = imports.misc.util; const History = imports.misc.history; @@ -33,7 +32,6 @@ const EXEC_ARG_KEY = 'exec-arg'; const SHOW_COMPLETIONS_KEY = 'run-dialog-show-completions'; const ALIASES_KEY = 'run-dialog-aliases'; -const DIALOG_GROW_TIME = 0.1; const MAX_COMPLETIONS = 40; const NAVIGATE_TYPE_NONE = 0; @@ -146,63 +144,61 @@ function completeCommand(text) { return [common.substring(last.length, common.length), results.map(x => x.substring(last.length, x.length))]; } -function RunDialog() { - this._init(); -} - -RunDialog.prototype = { -__proto__: ModalDialog.ModalDialog.prototype, - _init : function() { - ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'run-dialog' }); +var RunDialog = GObject.registerClass( +class RunDialog extends ModalDialog.ModalDialog { + _init() { + super._init({ styleClass: 'run-dialog'}); this._lockdownSettings = new Gio.Settings({ schema_id: LOCKDOWN_SCHEMA }); this._terminalSettings = new Gio.Settings({ schema_id: TERMINAL_SCHEMA }); - global.settings.connect('changed::development-tools', Lang.bind(this, function () { + global.settings.connect('changed::development-tools', () => { this._enableInternalCommands = global.settings.get_boolean('development-tools'); - })); + }); this._enableInternalCommands = global.settings.get_boolean('development-tools'); global.display.connect('restart', () => this.close()); - let label = new St.Label({ style_class: 'run-dialog-label', - text: _("Enter a command") }); + let title = _("Run a Command"); - this.contentLayout.add(label, { x_align: St.Align.MIDDLE }); + let content = new Dialog.MessageDialogContent({ title }); + this.contentLayout.add_actor(content); let entry = new St.Entry({ style_class: 'run-dialog-entry' }); CinnamonEntry.addContextMenu(entry); - entry.label_actor = label; - this._entryText = entry.clutter_text; this._oldText = ""; - this.contentLayout.add(entry, { y_align: St.Align.START }); + content.add_child(entry); this.setInitialKeyFocus(this._entryText); this._completionBox = new St.Label({style_class: 'run-dialog-completion-box'}); - this.contentLayout.add(this._completionBox); + content.add_child(this._completionBox); this._completionSelected = 0; let defaultDescriptionText = _("Press ESC to close"); - this._descriptionLabel = new St.Label({ style_class: 'run-dialog-description', - text: defaultDescriptionText }); + this._descriptionLabel = new St.Label({ + style_class: 'run-dialog-description', + text: defaultDescriptionText + }); this._descriptionLabel.clutter_text.line_wrap = true; this._descriptionLabel.clutter_text.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR); - this.contentLayout.add(this._descriptionLabel, { y_align: St.Align.MIDDLE }); + content.add_child(this._descriptionLabel); this._commandError = false; - this._entryText.connect('key-press-event', Lang.bind(this, this._onKeyPress)); + this._entryText.connect('key-press-event', this._onKeyPress.bind(this)); - this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY, - entry: this._entryText, - deduplicate: true }); + this._history = new History.HistoryManager({ + gsettingsKey: HISTORY_KEY, + entry: this._entryText, + deduplicate: true + }); this._updateCompletionTimer = 0; - }, + } - _onKeyPress: function (o, e) { + _onKeyPress(o, e) { let symbol = e.get_key_symbol(); if (symbol === Clutter.KEY_Return || symbol === Clutter.KEY_KP_Enter) { if (o.get_text().trim() == "") { @@ -266,15 +262,15 @@ __proto__: ModalDialog.ModalDialog.prototype, this._updateCompletionTimer = 0; } - this._updateCompletionTimer = Mainloop.timeout_add(200, Lang.bind(this, this._updateCompletions)); + this._updateCompletionTimer = Mainloop.timeout_add(200, this._updateCompletions.bind(this)); return false; } return false; - }, + } // There is different behaviour depending on whether this is called due to // pressing tab or other keys. - _updateCompletions: function(nav_type=NAVIGATE_TYPE_NONE, direction=DOWN) { + _updateCompletions(nav_type=NAVIGATE_TYPE_NONE, direction=DOWN) { this._updateCompletionTimer = 0; let text = this._expandHome(this._entryText.get_text()); @@ -339,18 +335,18 @@ __proto__: ModalDialog.ModalDialog.prototype, this._completionBox.hide(); this._oldText = ""; } - }, + } - _expandHome: function(text) { + _expandHome(text) { if (text.charAt(0) == '~') { text = text.slice(1); return GLib.build_filenamev([GLib.get_home_dir(), text]); } return text; - }, + } - _showCompletions: function(orig) { + _showCompletions(orig) { /* Show a list of possible completions, and allow users to scroll * through them. The scrolling mechanism is done in _updateCompletions, * which provides the current selected index in @@ -390,9 +386,9 @@ __proto__: ModalDialog.ModalDialog.prototype, this._completionBox.clutter_text.set_markup(text); this._entryText.set_selection(-1, orig.length); - }, + } - _run : function(input, inTerminal) { + _run(input, inTerminal) { input = input.trim(); this._history.addItem(input); this._commandError = false; @@ -419,8 +415,8 @@ __proto__: ModalDialog.ModalDialog.prototype, try { if (inTerminal) { let exec = this._terminalSettings.get_string(EXEC_KEY); - let exec_arg = this._terminalSettings.get_string(EXEC_ARG_KEY); - command = exec + ' ' + exec_arg + ' ' + input; + let execArg = this._terminalSettings.get_string(EXEC_ARG_KEY); + command = exec + ' ' + execArg + ' ' + input; } Util.spawnCommandLineAsync(command, null, null); } catch (e) { @@ -450,16 +446,16 @@ __proto__: ModalDialog.ModalDialog.prototype, this._showError(e.message); } } - }, + } - _showError : function(message) { + _showError(message) { this._commandError = true; this._descriptionLabel.set_text(message.trim()); this._descriptionLabel.add_style_class_name('error'); - }, + } - open: function() { + open() { this._history.lastItem(); this._descriptionLabel.set_text(_("Press ESC to close")); this._descriptionLabel.remove_style_class_name('error'); @@ -470,7 +466,6 @@ __proto__: ModalDialog.ModalDialog.prototype, if (this._lockdownSettings.get_boolean(DISABLE_COMMAND_LINE_KEY)) return; - ModalDialog.ModalDialog.prototype.open.call(this); - }, -}; -Signals.addSignalMethods(RunDialog.prototype); + super.open(); + } +}); diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js index 9901ccaef4..8fd516c035 100644 --- a/js/ui/windowManager.js +++ b/js/ui/windowManager.js @@ -13,6 +13,7 @@ const GObject = imports.gi.GObject; const AppSwitcher = imports.ui.appSwitcher.appSwitcher; const ModalDialog = imports.ui.modalDialog; const WmGtkDialogs = imports.ui.wmGtkDialogs; +const WorkspaceOsd = imports.ui.workspaceOsd; const {CoverflowSwitcher} = imports.ui.appSwitcher.coverflowSwitcher; const {TimelineSwitcher} = imports.ui.appSwitcher.timelineSwitcher; @@ -262,7 +263,7 @@ var WindowManager = class WindowManager { this._dimmedWindows = []; this._animationBlockCount = 0; this._switchData = null; - this._workspaceOSDs = []; + this._workspaceOsds = []; this._cinnamonwm.connect('kill-window-effects', (cinnamonwm, actor) => { this._unminimizeWindowDone(cinnamonwm, actor); @@ -1232,54 +1233,30 @@ var WindowManager = class WindowManager { } showWorkspaceOSD() { - this._hideWorkspaceOSD(true); if (global.settings.get_boolean('workspace-osd-visible')) { - let current_workspace_index = global.workspace_manager.get_active_workspace_index(); + let currentWorkspaceIndex = global.workspace_manager.get_active_workspace_index(); if (this.wm_settings.get_boolean('workspaces-only-on-primary')) { - this._showWorkspaceOSDOnMonitor(Main.layoutManager.primaryMonitor.index, current_workspace_index); - } - else { - let {monitors} = Main.layoutManager; - for (let i = 0; i < monitors.length; i++) { - this._showWorkspaceOSDOnMonitor(i, current_workspace_index); + this._showWorkspaceOSDForMonitor(Main.layoutManager.primaryMonitor.index, currentWorkspaceIndex); + } else { + for (let i = 0; i < Main.layoutManager.monitors.length; i++) { + this._showWorkspaceOSDForMonitor(i, currentWorkspaceIndex); } } } } - _showWorkspaceOSDOnMonitor(monitor, current_workspace_index) { - let osd = new ModalDialog.InfoOSD(); - osd.actor.add_style_class_name('workspace-osd'); - this._workspace_osd_array.push(osd); - osd.addText(Main.getWorkspaceName(current_workspace_index)); - osd.show(monitor); - - osd.actor.ease({ - z_position: -.0001, - duration: WORKSPACE_OSD_TIMEOUT * EASING_MULTIPLIER, - onComplete: () => this._hideWorkspaceOSD() - }) - } - - _hideWorkspaceOSD(now = false) { - for (let i = 0; i < this._workspace_osd_array.length; i++) { - let osd = this._workspace_osd_array[i]; - if (now) { - osd.actor.remove_all_transitions(); - osd.destroy(); - continue; - } - if (osd != null) { - osd.actor.opacity = 255; - osd.actor.ease({ - opacity: 0, - duration: WORKSPACE_OSD_TIMEOUT * EASING_MULTIPLIER, - mode: Clutter.AnimationMode.LINEAR, - onStopped: () => osd.destroy() - }); - } + _showWorkspaceOSDForMonitor(index, currentWorkspaceIndex) { + if (this._workspaceOsds[index] == null) { + let osd = new WorkspaceOsd.WorkspaceOsd(index); + this._workspaceOsds.push(osd); + osd.connect('destroy', () => { + this._workspaceOsds[index] = null; + this._workspaceOsds.splice(index, 1); + }); } - this._workspace_osd_array = []; + + let text = Main.getWorkspaceName(currentWorkspaceIndex); + this._workspaceOsds[index].display(currentWorkspaceIndex, text); } _showWindowMenu(cinnamonwm, window, menu, rect) { diff --git a/js/ui/workspaceOsd.js b/js/ui/workspaceOsd.js new file mode 100644 index 0000000000..31a285479f --- /dev/null +++ b/js/ui/workspaceOsd.js @@ -0,0 +1,126 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Clutter = imports.gi.Clutter; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; +const St = imports.gi.St; + +const Layout = imports.ui.layout; +const Main = imports.ui.main; + +var ANIMATION_TIME = 100; +var DISPLAY_TIMEOUT = 600; + + +var WorkspaceOsd = GObject.registerClass( +class WorkspaceOsd extends Clutter.Actor { + _init(monitorIndex) { + super._init({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.END, + }); + + this._monitorIndex = monitorIndex; + + this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); + + let constraint = new Layout.MonitorConstraint({ index: monitorIndex }); + this.add_constraint(constraint); + + Main.uiGroup.add_actor(this); + + this._timeoutId = 0; + + this._vbox = new St.BoxLayout({ + style_class: 'workspace-switch-osd', + important: true, + vertical: true, + }); + this.add_child(this._vbox); + + this._label = new St.Label(); + this._vbox.add_child(this._label); + + this._list = new St.BoxLayout({ + style_class: 'workspace-switch-osd-indicator-box', + }); + this._vbox.add_child(this._list); + + this._redisplay(); + + this.hide(); + + let workspaceManager = global.workspace_manager; + this._workspaceManagerSignals = []; + this._workspaceManagerSignals.push(workspaceManager.connect('workspace-added', + this._redisplay.bind(this))); + this._workspaceManagerSignals.push(workspaceManager.connect('workspace-removed', + this._redisplay.bind(this))); + + this.connect('destroy', this._onDestroy.bind(this)); + } + + _redisplay() { + let workspaceManager = global.workspace_manager; + + this._list.destroy_all_children(); + + for (let i = 0; i < workspaceManager.n_workspaces; i++) { + const indicator = new St.Bin({ + style_class: 'workspace-switch-osd-indicator', + }); + + if (i === this._activeWorkspaceIndex) + indicator.add_style_pseudo_class('active'); + + this._list.add_actor(indicator); + } + } + + display(activeWorkspaceIndex, workspaceName) { + this._activeWorkspaceIndex = activeWorkspaceIndex; + this._label.text = workspaceName; + + this._redisplay(); + if (this._timeoutId != 0) + GLib.source_remove(this._timeoutId); + this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, DISPLAY_TIMEOUT, this._onTimeout.bind(this)); + GLib.Source.set_name_by_id(this._timeoutId, '[cinnamon] this._onTimeout'); + + const duration = this.visible ? 0 : ANIMATION_TIME; + this.show(); + this.opacity = 0; + this.ease({ + opacity: 255, + duration, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); + } + + _onTimeout() { + GLib.source_remove(this._timeoutId); + this._timeoutId = 0; + this.ease({ + opacity: 0.0, + duration: ANIMATION_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => this.destroy(), + }); + return GLib.SOURCE_REMOVE; + } + + _onDestroy() { + if (this._timeoutId) + GLib.source_remove(this._timeoutId); + this._timeoutId = 0; + + let workspaceManager = global.workspace_manager; + for (let i = 0; i < this._workspaceManagerSignals.length; i++) + workspaceManager.disconnect(this._workspaceManagerSignals[i]); + + this._workspaceManagerSignals = []; + } +}); diff --git a/src/st/st-entry.c b/src/st/st-entry.c index fb9856ba61..06c37c003c 100644 --- a/src/st/st-entry.c +++ b/src/st/st-entry.c @@ -34,7 +34,7 @@ * focus: the widget has focus * * - * indeterminate: the widget is showing the hint text + * indeterminate: the widget is showing the hint text or actor * * * hover: the widget is showing the hint text and is underneath the @@ -61,6 +61,7 @@ // #include "st-im-text.h" #include "st-icon.h" +#include "st-label.h" #include "st-widget.h" #include "st-texture-cache.h" #include "st-clipboard.h" @@ -78,6 +79,7 @@ enum PROP_CLUTTER_TEXT, PROP_HINT_TEXT, + PROP_HINT_ACTOR, PROP_TEXT, }; @@ -104,6 +106,8 @@ struct _StEntryPrivate ClutterActor *primary_icon; ClutterActor *secondary_icon; + ClutterActor *hint_actor; + gfloat spacing; gboolean hint_visible; @@ -111,6 +115,10 @@ struct _StEntryPrivate guint blink_time; guint blink_timeout; gboolean cursor_visible; + + CoglPipeline *text_shadow_material; + gfloat shadow_width; + gfloat shadow_height; }; static guint entry_signals[LAST_SIGNAL] = { 0, }; @@ -133,6 +141,10 @@ st_entry_set_property (GObject *gobject, st_entry_set_hint_text (entry, g_value_get_string (value)); break; + case PROP_HINT_ACTOR: + st_entry_set_hint_actor (entry, g_value_get_object (value)); + break; + case PROP_TEXT: st_entry_set_text (entry, g_value_get_string (value)); break; @@ -158,7 +170,11 @@ st_entry_get_property (GObject *gobject, break; case PROP_HINT_TEXT: - g_value_set_string (value, priv->hint); + g_value_set_string (value, st_entry_get_hint_text (ST_ENTRY (gobject))); + break; + + case PROP_HINT_ACTOR: + g_value_set_object (value, priv->hint_actor); break; case PROP_TEXT: @@ -220,6 +236,8 @@ st_entry_dispose (GObject *object) ClutterKeymap *keymap; ClutterSeat *seat; + cogl_clear_object (&priv->text_shadow_material); + if (priv->blink_timeout) { g_source_remove (priv->blink_timeout); @@ -234,14 +252,20 @@ st_entry_dispose (GObject *object) } static void -st_entry_finalize (GObject *object) +st_entry_update_hint_visibility (StEntry *self) { - StEntryPrivate *priv = ST_ENTRY_PRIV (object); + StEntryPrivate *priv = ST_ENTRY_PRIV (self); + gboolean hint_visible = + priv->hint_actor != NULL && + strcmp (clutter_text_get_text (CLUTTER_TEXT (priv->entry)), "") == 0; - g_free (priv->hint); - priv->hint = NULL; + if (priv->hint_actor) + g_object_set (priv->hint_actor, "visible", hint_visible, NULL); - G_OBJECT_CLASS (st_entry_parent_class)->finalize (object); + if (hint_visible) + st_widget_add_style_pseudo_class (ST_WIDGET (self), "indeterminate"); + else + st_widget_remove_style_pseudo_class (ST_WIDGET (self), "indeterminate"); } static void @@ -252,6 +276,8 @@ st_entry_style_changed (StWidget *self) ClutterColor color; gdouble size; + cogl_clear_object (&priv->text_shadow_material); + theme_node = st_widget_get_theme_node (self); if (st_theme_node_lookup_length (theme_node, "caret-size", TRUE, &size)) @@ -302,7 +328,7 @@ st_entry_get_preferred_width (ClutterActor *actor, { StEntryPrivate *priv = ST_ENTRY_PRIV (actor); StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); - gfloat icon_w; + gfloat hint_w, icon_w; st_theme_node_adjust_for_height (theme_node, &for_height); @@ -310,6 +336,17 @@ st_entry_get_preferred_width (ClutterActor *actor, min_width_p, natural_width_p); + if (priv->hint_actor) + { + clutter_actor_get_preferred_width (priv->hint_actor, -1, NULL, &hint_w); + + if (min_width_p && hint_w > *min_width_p) + *min_width_p = hint_w; + + if (natural_width_p && hint_w > *natural_width_p) + *natural_width_p = hint_w; + } + if (priv->primary_icon) { clutter_actor_get_preferred_width (priv->primary_icon, -1, NULL, &icon_w); @@ -344,7 +381,7 @@ st_entry_get_preferred_height (ClutterActor *actor, { StEntryPrivate *priv = ST_ENTRY_PRIV (actor); StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); - gfloat icon_h; + gfloat hint_h, icon_h; st_theme_node_adjust_for_width (theme_node, &for_width); @@ -352,6 +389,17 @@ st_entry_get_preferred_height (ClutterActor *actor, min_height_p, natural_height_p); + if (priv->hint_actor) + { + clutter_actor_get_preferred_height (priv->hint_actor, -1, NULL, &hint_h); + + if (min_height_p && hint_h > *min_height_p) + *min_height_p = hint_h; + + if (natural_height_p && hint_h > *natural_height_p) + *natural_height_p = hint_h; + } + if (priv->primary_icon) { clutter_actor_get_preferred_height (priv->primary_icon, @@ -386,9 +434,13 @@ st_entry_allocate (ClutterActor *actor, { StEntryPrivate *priv = ST_ENTRY_PRIV (actor); StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); - ClutterActorBox content_box, child_box, icon_box; + ClutterActorBox content_box, child_box, icon_box, hint_box; gfloat icon_w, icon_h; + gfloat hint_w, hint_h; gfloat entry_h, min_h, pref_h, avail_h; + gboolean is_rtl; + + is_rtl = clutter_actor_get_text_direction (actor) == CLUTTER_TEXT_DIRECTION_RTL; clutter_actor_set_allocation (actor, box, flags); @@ -441,6 +493,25 @@ st_entry_allocate (ClutterActor *actor, child_box.x2 = MAX (child_box.x1, child_box.x2 - icon_w - priv->spacing); } + if (priv->hint_actor) + { + /* now allocate the hint actor */ + hint_box = child_box; + + clutter_actor_get_preferred_width (priv->hint_actor, -1, NULL, &hint_w); + clutter_actor_get_preferred_height (priv->hint_actor, -1, NULL, &hint_h); + + if (is_rtl) + hint_box.x1 = hint_box.x2 - hint_w; + else + hint_box.x2 = hint_box.x1 + hint_w; + + hint_box.y1 = ceil (content_box.y1 + avail_h / 2 - hint_h / 2); + hint_box.y2 = hint_box.y1 + hint_h; + + clutter_actor_allocate (priv->hint_actor, &hint_box, flags); + } + clutter_actor_get_preferred_height (priv->entry, child_box.x2 - child_box.x1, &min_h, &pref_h); @@ -632,18 +703,9 @@ clutter_text_focus_in_cb (ClutterText *text, ClutterActor *actor) { StEntry *entry = ST_ENTRY (actor); - StEntryPrivate *priv = entry->priv; ClutterSeat *seat; ClutterKeymap *keymap; - /* remove the hint if visible */ - if (priv->hint && priv->hint_visible) - { - priv->hint_visible = FALSE; - - clutter_text_set_text (text, ""); - } - seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); keymap = clutter_seat_get_keymap (seat); @@ -651,7 +713,6 @@ clutter_text_focus_in_cb (ClutterText *text, g_signal_connect (keymap, "state-changed", G_CALLBACK (keymap_state_changed), entry); - st_widget_remove_style_pseudo_class (ST_WIDGET (actor), "indeterminate"); st_widget_add_style_pseudo_class (ST_WIDGET (actor), "focus"); st_entry_reset_blink_time (entry); @@ -663,20 +724,11 @@ clutter_text_focus_out_cb (ClutterText *text, ClutterActor *actor) { StEntry *entry = ST_ENTRY (actor); - StEntryPrivate *priv = entry->priv; ClutterKeymap *keymap; ClutterSeat *seat; st_widget_remove_style_pseudo_class (ST_WIDGET (actor), "focus"); - /* add a hint if the entry is empty */ - if (priv->hint && !strcmp (clutter_text_get_text (text), "")) - { - priv->hint_visible = TRUE; - - clutter_text_set_text (text, priv->hint); - st_widget_add_style_pseudo_class (ST_WIDGET (actor), "indeterminate"); - } st_entry_check_cursor_blink (entry); remove_capslock_feedback (entry); @@ -714,6 +766,22 @@ clutter_text_cursor_changed (ClutterText *text, ClutterActor *actor) st_entry_pend_cursor_blink (ST_ENTRY (actor)); } +static void +clutter_text_changed_cb (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + StEntry *entry = ST_ENTRY (user_data); + StEntryPrivate *priv = ST_ENTRY_PRIV (entry); + + st_entry_update_hint_visibility (entry); + + /* Since the text changed, force a regen of the shadow texture */ + cogl_clear_object (&priv->text_shadow_material); + + g_object_notify (G_OBJECT (entry), "text"); +} + static void st_entry_clipboard_callback (StClipboard *clipboard, const gchar *text, @@ -854,6 +922,62 @@ st_entry_key_focus_in (ClutterActor *actor) clutter_actor_grab_key_focus (priv->entry); } +static void +st_entry_paint (ClutterActor *actor, + ClutterPaintContext *paint_context) +{ + StEntryPrivate *priv = ST_ENTRY_PRIV (actor); + StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); + StShadow *shadow_spec = st_theme_node_get_text_shadow (theme_node); + ClutterActorClass *parent_class; + + st_widget_paint_background (ST_WIDGET (actor), paint_context); + + if (shadow_spec) + { + ClutterActorBox allocation; + float width, height; + + clutter_actor_get_allocation_box (priv->entry, &allocation); + clutter_actor_box_get_size (&allocation, &width, &height); + + if (priv->text_shadow_material == NULL || + width != priv->shadow_width || + height != priv->shadow_height) + { + CoglPipeline *material; + + cogl_clear_object (&priv->text_shadow_material); + + material = _st_create_shadow_pipeline_from_actor (shadow_spec, + priv->entry); + + priv->shadow_width = width; + priv->shadow_height = height; + priv->text_shadow_material = material; + } + + if (priv->text_shadow_material != NULL) + { + CoglFramebuffer *framebuffer = + clutter_paint_context_get_framebuffer (paint_context); + + _st_paint_shadow_with_opacity (shadow_spec, + framebuffer, + priv->text_shadow_material, + &allocation, + clutter_actor_get_paint_opacity (priv->entry)); + } + } + + /* Since we paint the background ourselves, chain to the parent class + * of StWidget, to avoid painting it twice. + * This is needed as we still want to paint children. + */ + parent_class = g_type_class_peek_parent (st_entry_parent_class); + parent_class->paint (actor, paint_context); +} + static void st_entry_class_init (StEntryClass *klass) { @@ -864,12 +988,12 @@ st_entry_class_init (StEntryClass *klass) gobject_class->set_property = st_entry_set_property; gobject_class->get_property = st_entry_get_property; - gobject_class->finalize = st_entry_finalize; gobject_class->dispose = st_entry_dispose; actor_class->get_preferred_width = st_entry_get_preferred_width; actor_class->get_preferred_height = st_entry_get_preferred_height; actor_class->allocate = st_entry_allocate; + actor_class->paint = st_entry_paint; actor_class->key_press_event = st_entry_key_press_event; actor_class->key_focus_in = st_entry_key_focus_in; @@ -892,6 +1016,14 @@ st_entry_class_init (StEntryClass *klass) NULL, G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_HINT_TEXT, pspec); + pspec = g_param_spec_object ("hint-actor", + "Hint Actor", + "An actor to display when the entry is not focused " + "and the text property is empty", + CLUTTER_TYPE_ACTOR, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_HINT_ACTOR, pspec); + pspec = g_param_spec_string ("text", "Text", "Text of the entry", @@ -957,8 +1089,15 @@ st_entry_init (StEntry *entry) g_signal_connect (priv->entry, "cursor-changed", G_CALLBACK (clutter_text_cursor_changed), entry); + g_signal_connect (priv->entry, "notify::text", + G_CALLBACK (clutter_text_changed_cb), entry); + priv->spacing = 6.0f; + priv->text_shadow_material = NULL; + priv->shadow_width = -1.; + priv->shadow_height = -1.; + clutter_actor_add_child (CLUTTER_ACTOR (entry), priv->entry); clutter_actor_set_reactive ((ClutterActor *) entry, TRUE); @@ -1003,10 +1142,7 @@ st_entry_get_text (StEntry *entry) { g_return_val_if_fail (ST_IS_ENTRY (entry), NULL); - if (entry->priv->hint_visible) - return ""; - else - return clutter_text_get_text (CLUTTER_TEXT (entry->priv->entry)); + return clutter_text_get_text (CLUTTER_TEXT (entry->priv->entry)); } /** @@ -1026,25 +1162,10 @@ st_entry_set_text (StEntry *entry, priv = entry->priv; - /* set a hint if we are blanking the entry */ - if (priv->hint - && text && !strcmp ("", text) - && !HAS_FOCUS (priv->entry)) - { - text = priv->hint; - priv->hint_visible = TRUE; - st_widget_add_style_pseudo_class (ST_WIDGET (entry), "indeterminate"); - } - else - { - st_widget_remove_style_pseudo_class (ST_WIDGET (entry), "indeterminate"); - - priv->hint_visible = FALSE; - } - clutter_text_set_text (CLUTTER_TEXT (priv->entry), text); - g_object_notify (G_OBJECT (entry), "text"); + /* Note: PROP_TEXT will get notfied from our notify::text handler connected + * to priv->entry. */ } /** @@ -1077,24 +1198,14 @@ void st_entry_set_hint_text (StEntry *entry, const gchar *text) { - StEntryPrivate *priv; + StWidget *label; g_return_if_fail (ST_IS_ENTRY (entry)); - priv = entry->priv; - - g_free (priv->hint); - - priv->hint = g_strdup (text); - - if (!strcmp (clutter_text_get_text (CLUTTER_TEXT (priv->entry)), "") - && !HAS_FOCUS (priv->entry)) - { - priv->hint_visible = TRUE; + label = st_label_new (text); + st_widget_add_style_class_name (label, "hint-text"); - clutter_text_set_text (CLUTTER_TEXT (priv->entry), priv->hint); - st_widget_add_style_pseudo_class (ST_WIDGET (entry), "indeterminate"); - } + st_entry_set_hint_actor (ST_ENTRY (entry), CLUTTER_ACTOR (label)); } /** @@ -1109,9 +1220,16 @@ st_entry_set_hint_text (StEntry *entry, const gchar * st_entry_get_hint_text (StEntry *entry) { + StEntryPrivate *priv; + g_return_val_if_fail (ST_IS_ENTRY (entry), NULL); - return entry->priv->hint; + priv = entry->priv; + + if (priv->hint_actor != NULL && ST_IS_LABEL (priv->hint_actor)) + return st_label_get_text (ST_LABEL (priv->hint_actor)); + + return NULL; } static gboolean @@ -1264,6 +1382,57 @@ st_entry_set_secondary_icon_from_file (StEntry *entry, } +/** + * st_entry_set_hint_actor: + * @entry: a #StEntry + * @hint_actor: (allow-none): a #ClutterActor + * + * Set the hint actor of the entry to @hint_actor + */ +void +st_entry_set_hint_actor (StEntry *entry, + ClutterActor *hint_actor) +{ + StEntryPrivate *priv; + + g_return_if_fail (ST_IS_ENTRY (entry)); + + priv = entry->priv; + + if (priv->hint_actor != NULL) + { + clutter_actor_remove_child (CLUTTER_ACTOR (entry), priv->hint_actor); + priv->hint_actor = NULL; + } + + if (hint_actor != NULL) + { + priv->hint_actor = hint_actor; + clutter_actor_add_child (CLUTTER_ACTOR (entry), priv->hint_actor); + } + + st_entry_update_hint_visibility (entry); + + clutter_actor_queue_relayout (CLUTTER_ACTOR (entry)); +} + +/** + * st_entry_get_hint_actor: + * @entry: a #StEntry + * + * Returns: (transfer none): a #ClutterActor + */ +ClutterActor * +st_entry_get_hint_actor (StEntry *entry) +{ + StEntryPrivate *priv; + + g_return_val_if_fail (ST_IS_ENTRY (entry), NULL); + + priv = entry->priv; + return priv->hint_actor; +} + /******************************************************************************/ /*************************** ACCESSIBILITY SUPPORT ****************************/ /******************************************************************************/ diff --git a/src/st/st-entry.h b/src/st/st-entry.h index cded2e7c52..516c33da65 100644 --- a/src/st/st-entry.h +++ b/src/st/st-entry.h @@ -82,6 +82,9 @@ void st_entry_set_primary_icon_from_file (StEntry *entry, const gchar *filename); void st_entry_set_secondary_icon_from_file (StEntry *entry, const gchar *filename); +void st_entry_set_hint_actor (StEntry *entry, + ClutterActor *hint_actor); +ClutterActor * st_entry_get_hint_actor (StEntry *entry); G_END_DECLS diff --git a/src/st/st-widget.c b/src/st/st-widget.c index 3263536b24..26acdc2bbd 100644 --- a/src/st/st-widget.c +++ b/src/st/st-widget.c @@ -1489,6 +1489,17 @@ st_widget_name_notify (StWidget *widget, st_widget_style_changed (widget); } +static void +st_widget_reactive_notify (StWidget *widget, + GParamSpec *pspec, + gpointer data) +{ + if (clutter_actor_get_reactive (CLUTTER_ACTOR (widget))) + st_widget_remove_style_pseudo_class (widget, "insensitive"); + else + st_widget_add_style_pseudo_class (widget, "insensitive"); +} + static void st_widget_first_child_notify (StWidget *widget, GParamSpec *pspec, @@ -1552,6 +1563,7 @@ st_widget_init (StWidget *actor) /* connect style changed */ g_signal_connect (actor, "notify::name", G_CALLBACK (st_widget_name_notify), NULL); + g_signal_connect (actor, "notify::reactive", G_CALLBACK (st_widget_reactive_notify), NULL); g_signal_connect (actor, "notify::first-child", G_CALLBACK (st_widget_first_child_notify), NULL); g_signal_connect (actor, "notify::last-child", G_CALLBACK (st_widget_last_child_notify), NULL);