Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/gui/qt/style/gtkthemeprovider/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 19 kB image not shown  

Quelle  gtk_util.cpp   Sprache: C

 

/*****************************************************************************
 * Copyright (C) 2022 VLC authors and VideoLAN
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * ( at your option ) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


// original code from the Chromium project

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gtk_util.h"
#include "gtk_compat.h"
#include <gdk/gdk.h>

#include <locale.h>
#include <stddef.h>

#include <memory>
#include <cmath>

namespace gtk {

namespace {

GtkCssContext AppendCssNodeToStyleContextImpl(
        GtkCssContext context,
        GType gtype,
        const std::string& name,
        const std::string& object_name,
        const std::vector<std::string>& classes,
        GtkStateFlags state,
        float scale) {
#if 0 //FIXME GTK4
    if (GtkCheckVersion(4)) {
        // GTK_TYPE_BOX is used instead of GTK_TYPE_WIDGET because:
        // 1. Widgets are abstract and cannot be created directly.
        // 2. The widget must be a container type so that it unrefs child widgets
        //    on destruction.
        auto* widget_object = object_name.empty()
                ? g_object_new(GTK_TYPE_BOX, nullptr)
                : g_object_new(GTK_TYPE_BOX, "css-name",
                               object_name.c_str(), nullptr);
        auto widget = TakeGObject(GTK_WIDGET(widget_object));

        if (!name.empty())
            gtk_widget_set_name(widget, name.c_str());

        std::vector<const char*> css_classes;
        css_classes.reserve(classes.size() + 1);
        for (const auto& css_class : classes)
            css_classes.push_back(css_class.c_str());
        css_classes.push_back(nullptr);
        gtk_widget_set_css_classes(widget, css_classes.data());

        gtk_widget_set_state_flags(widget, state, false);

        if (context)
            gtk_widget_set_parent(widget, context.widget());

        gtk_style_context_set_scale(gtk_widget_get_style_context(widget), scale);

        return GtkCssContext(widget, context ? context.root() : widget);
    } else
#endif
    {
        GtkWidgetPath* path =
                context ? gtk_widget_path_copy(gtk_style_context_get_path(context))
                        : gtk_widget_path_new();
        gtk_widget_path_append_type(path, gtype);

        if (!object_name.empty()) {
            if (GtkCheckVersion(3, 20))
                gtk_widget_path_iter_set_object_name(path, -1, object_name.c_str());
            else
                gtk_widget_path_iter_add_class(path, -1, object_name.c_str());
        }

        if (!name.empty())
            gtk_widget_path_iter_set_name(path, -1, name.c_str());

        for (const auto& css_class : classes)
            gtk_widget_path_iter_add_class(path, -1, css_class.c_str());

        if (GtkCheckVersion(3, 14))
            gtk_widget_path_iter_set_state(path, -1, state);

        GtkCssContext child_context(TakeGObject(gtk_style_context_new()));
        gtk_style_context_set_path(child_context, path);
        if (GtkCheckVersion(3, 14)) {
            gtk_style_context_set_state(child_context, state);
        } else {
            GtkStateFlags child_state = state;
            if (context) {
                child_state = static_cast<GtkStateFlags>(
                            child_state | gtk_style_context_get_state(context));
            }
            gtk_style_context_set_state(child_context, child_state);
        }

        gtk_style_context_set_scale(child_context, scale);

        gtk_style_context_set_parent(child_context, context);

        gtk_widget_path_unref(path);
        return GtkCssContext(std::move(child_context));
    }
}

GtkWidget* CreateDummyWindow() {
    GtkWidget* window =   gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_widget_realize(window);
    return window;
}

}  // namespace

bool GtkCheckVersion(uint32_t major, uint32_t minor, uint32_t micro) {
    if (major < gtk_get_major_version())
        return true;
    else if (major > gtk_get_major_version())
        return false;

    if (minor < gtk_get_minor_version())
        return true;
    else if (minor > gtk_get_minor_version())
        return false;

    return micro <= gtk_get_micro_version();
}

const char* GtkCssMenu() {
    return GtkCheckVersion(4) ? "#popover.background.menu #contents"
                              : "GtkMenu#menu";
}

const char* GtkCssMenuItem() {
    return GtkCheckVersion(4) ? "#modelbutton.flat" : "GtkMenuItem#menuitem";
}

const char* GtkCssMenuScrollbar() {
    return GtkCheckVersion(4) ? "#scrollbar #range"
                              : "GtkScrollbar#scrollbar #trough";
}

bool GtkInitFromCommandLine(int* argc, char** argv) {
    // Callers should have already called setlocale(LC_ALL, "") and
    // setlocale(LC_NUMERIC, "C") by now. Chrome does this in
    // service_manager::Main.
    assert(strcmp(setlocale(LC_NUMERIC, nullptr), "C") == 0);
    // This prevents GTK from calling setlocale(LC_ALL, ""), which potentially
    // overwrites the LC_NUMERIC locale to something other than "C".
    gtk_disable_setlocale();
    return gtk_init_check(argc, &argv);
}


CairoSurface::CairoSurface(VLCPicturePtr& bitmap) 
{
    picture_t* pic = bitmap.get();
    surface_ = (cairo_image_surface_create_for_data(
                   static_cast<unsigned char*>(pic->p[0].p_pixels),
                   CAIRO_FORMAT_ARGB32,
                   pic->format.i_visible_width,
                   pic->format.i_visible_height,
                   pic->p[0].i_pitch));
    cairo_ = cairo_create(surface_);
}

CairoSurface::CairoSurface(const MySize& size)
    : surface_(cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
                                          size.width(),
                                          size.height())),
      cairo_(cairo_create(surface_)) {
    assert(cairo_surface_status(surface_) == CAIRO_STATUS_SUCCESS);
    // Clear the surface.
    cairo_save(cairo_);
    cairo_set_source_rgba(cairo_, 0, 0, 0, 0);
    cairo_set_operator(cairo_, CAIRO_OPERATOR_SOURCE);
    cairo_paint(cairo_);
    cairo_restore(cairo_);
}

CairoSurface::~CairoSurface() {
    // `cairo_destroy` and `cairo_surface_destroy` decrease the reference count on
    // `cairo_` and `surface_` objects respectively. The underlying memory is
    // freed if the reference count goes to zero. We use ExtractAsDangling() here
    // to avoid holding a briefly dangling ptr in case the memory is freed.
    cairo_destroy(cairo_);
    cairo_surface_destroy(surface_);
}



GdkRGBA CairoSurface::GetAveragePixelValue(bool frame) {
    cairo_surface_flush(surface_);
    unsigned char* data =cairo_image_surface_get_data(surface_);
    int width = cairo_image_surface_get_width(surface_);
    int height = cairo_image_surface_get_height(surface_);
    int stride = cairo_image_surface_get_stride(surface_);
    assert(cairo_image_surface_get_format(surface_) == CAIRO_FORMAT_ARGB32);
    long a = 0, r = 0, g = 0, b = 0;
    uint32_t max_alpha = 0;
    for (int line = 0; line < height; line++)
    {
        uint32_t* rgbaLine = (uint32_t*)(&data[line*stride]);
        for (int i = 0; i < width; i++) {
            uint32_t color =  rgbaLine[i];
            max_alpha = std::max((color >> 24) & 0xFF, max_alpha);
            a += (color >> 24) & 0xFF;
            r += (color >> 16) & 0xFF;
            g += (color >> 8) & 0xFF;
            b += (color)  & 0xFF;
        }
    }

    GdkRGBA out = {0,0,0,0};
    if (a == 0) {
        return out;
    }
    out.red = gdouble(r) / a;
    out.green = gdouble(g) / a;
    out.blue = gdouble(b) / a;
    out.alpha = frame ? (max_alpha / 255.) : gdouble(a) / (width * height * 255);
    return out;
}

GtkCssContext::GtkCssContext(GtkWidget* widget, GtkWidget* root)
    : widget_(widget), root_(WrapGObject(root)) {
    assert(GtkCheckVersion(4));
}

GtkCssContext::GtkCssContext(GtkStyleContext* context)
    : context_(WrapGObject(context)) {
    assert(!GtkCheckVersion(4));
}

GtkCssContext::GtkCssContext() = default;
GtkCssContext::GtkCssContext(const GtkCssContext&) = default;
GtkCssContext::GtkCssContext(GtkCssContext&&) = default;
GtkCssContext& GtkCssContext::operator=(const GtkCssContext&) = default;
GtkCssContext& GtkCssContext::operator=(GtkCssContext&&) = default;
GtkCssContext::~GtkCssContext() = default;

GtkCssContext::operator GtkStyleContext*() {
    if (GtkCheckVersion(4))
        return widget_ ? gtk_widget_get_style_context(widget_) : nullptr;
    return context_;
}

GtkCssContext GtkCssContext::GetParent() {
    if (GtkCheckVersion(4)) {
        return GtkCssContext(WrapGObject(gtk_widget_get_parent(widget_)),
                             root_ == widget_ ? ScopedGObject<GtkWidget>() : root_);
    }
    return GtkCssContext(WrapGObject(gtk_style_context_get_parent(context_)));
}

GtkWidget* GtkCssContext::widget() {
    assert(GtkCheckVersion(4));
    return widget_;
}

GtkWidget* GtkCssContext::root() {
    assert(GtkCheckVersion(4));
    return root_;
}


GtkCssContext AppendCssNodeToStyleContext(GtkCssContext context,
                                          const std::string& css_node) {
    enum {
        CSS_TYPE,
        CSS_NAME,
        CSS_OBJECT_NAME,
        CSS_CLASS,
        CSS_PSEUDOCLASS,
        CSS_NONE,
    } part_type = CSS_TYPE;

    static const struct {
        const char* name;
        GtkStateFlags state_flag;
    } pseudo_classes[] = {
    {"active", GTK_STATE_FLAG_ACTIVE},
    {"hover", GTK_STATE_FLAG_PRELIGHT},
    {"selected", GTK_STATE_FLAG_SELECTED},
    {"disabled", GTK_STATE_FLAG_INSENSITIVE},
    {"indeterminate", GTK_STATE_FLAG_INCONSISTENT},
    {"focus", GTK_STATE_FLAG_FOCUSED},
    {"backdrop", GTK_STATE_FLAG_BACKDROP},
    {"link", GTK_STATE_FLAG_LINK},
    {"visited", GTK_STATE_FLAG_VISITED},
    {"checked", GTK_STATE_FLAG_CHECKED},
};

    GType gtype = G_TYPE_NONE;
    std::string name;
    std::string object_name;
    std::vector<std::string> classes;
    GtkStateFlags state = GTK_STATE_FLAG_NORMAL;

    auto it = css_node.cbegin();

    //base::StringTokenizer t(css_node, ".:#()");
    //t.set_options(base::StringTokenizer::RETURN_DELIMS);
    while (it != css_node.cend()) {

        auto found = std::find_if(it, css_node.cend(), [](const char c) {
            return (c == '.') || (c == ':') || (c == '#') || (c == '(') || (c == ')');
        });

        std::string token(it, found);

        if (token != "")
        {
            switch (part_type) {
            case CSS_NAME:
                name = token;
                break;
            case CSS_OBJECT_NAME:
                object_name = token;
                break;
            case CSS_TYPE: {
                if (!GtkCheckVersion(4)) {
                    gtype = g_type_from_name(token.c_str());
                    assert(gtype);
                }
                break;
            }
            case CSS_CLASS:
                classes.push_back(std::move(token));
                break;
            case CSS_PSEUDOCLASS: {
                GtkStateFlags state_flag = GTK_STATE_FLAG_NORMAL;
                for (const auto& pseudo_class_entry : pseudo_classes) {
                    if (strcmp(pseudo_class_entry.name, token.c_str()) == 0) {
                        state_flag = pseudo_class_entry.state_flag;
                        break;
                    }
                }
                state = static_cast<GtkStateFlags>(state | state_flag);
                break;
            }
            case CSS_NONE:
                assert(false);
            }
        }

        if (found == css_node.cend())
            break;

        switch (*found) {
        case '(':
            part_type = CSS_NAME;
            break;
        case ')':
            part_type = CSS_NONE;
            break;
        case '#':
            part_type = CSS_OBJECT_NAME;
            break;
        case '.':
            part_type = CSS_CLASS;
            break;
        case ':':
            part_type = CSS_PSEUDOCLASS;
            break;
        default:
            assert("unreachable" == 0);
        }

        it = found + 1;
    }

    // Always add a "chromium" class so that themes can style chromium
    // widgets specially if they want to.
    classes.push_back("vlc");

    float scale = std::round(GetDeviceScaleFactor());

    return AppendCssNodeToStyleContextImpl(std::move(context), gtype, name, object_name,
                                           classes, state, scale);
}

GtkCssContext GetStyleContextFromCss(const std::string& css_selector) {
    // Prepend a window node to the selector since all widgets must live
    // in a window, but we don't want to specify that every time.
    auto context = AppendCssNodeToStyleContext({}, "GtkWindow#window.background");

    auto it = css_selector.cbegin();
    while (it != css_selector.cend())
    {
        auto found = std::find(it, css_selector.cend(), ' ');
        std::string widget_type(it, found);
        if (widget_type != "")
            context = AppendCssNodeToStyleContext(context, widget_type);

        if (found == css_selector.cend())
            break;

        it = found + 1;
    }
    return context;
}

GdkRGBA GetBgColorFromStyleContext(GtkCssContext context) {
    // Backgrounds are more general than solid colors (eg. gradients),
    // but chromium requires us to boil this down to one color.  We
    // cannot use the background-color here because some themes leave it
    // set to a garbage color because a background-image will cover it
    // anyway.  So we instead render the background into a 24x24 bitmap,
    // removing any borders, and hope that we get a good color.
    ApplyCssToContext(context,
                      "* {"
                      "border-radius: 0px;"
                      "border-style: none;"
                      "box-shadow: none;"
                      "}");
    MySize size(24, 24);
    CairoSurface surface(size);
    RenderBackground(size, surface.cairo(), std::move(context));
    return surface.GetAveragePixelValue(false);
}

GdkRGBA GtkStyleContextGetColor(GtkStyleContext* context) {
    GdkRGBA color;
    gtk_style_context_get_color(context, gtk_style_context_get_state(context), &color );
    return color;
}


GdkRGBA GetFgColor(const std::string& css_selector) {
    return GtkStyleContextGetColor(GetStyleContextFromCss(css_selector));
}



ScopedCssProvider GetCssProvider(const std::string& css) {
    auto provider = TakeGObject(gtk_css_provider_new());

    gtk_css_provider_load_from_data(provider, css.c_str(), -1, nullptr);
    return provider;
}

void ApplyCssProviderToContext(GtkCssContext context,
                               GtkCssProvider* provider) {
    while (context) {
        gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider),
                                       G_MAXUINT);
        context = context.GetParent();
    }
}

void ApplyCssToContext(GtkCssContext context, const std::string& css) {
    auto provider = GetCssProvider(css);
    ApplyCssProviderToContext(std::move(context), provider);
}

void RenderBackground(const MySize& size,
                      cairo_t* cr,
                      GtkCssContext context) {
    if (!context)
        return;
    RenderBackground(size, cr, context.GetParent());
    gtk_render_background(context, cr, 0, 0, size.width(), size.height());
}

GdkRGBA GetBgColor(const std::string& css_selector) {
    return GetBgColorFromStyleContext(GetStyleContextFromCss(css_selector));
}

GdkRGBA GetBorderColor(const std::string& css_selector) {
    // Borders have the same issue as backgrounds, due to the
    // border-image property.
    auto context = GetStyleContextFromCss(css_selector);
    MySize size(24, 24);
    CairoSurface surface(size);
    gtk_render_frame(context, surface.cairo(), 0, 0, size.width(), size.height());
    return surface.GetAveragePixelValue(true);
}

GdkRGBA GetFocusColor(const std::string& css_selector)
{
    auto context = GetStyleContextFromCss(css_selector);
    MySize size(24, 24);
    CairoSurface surface(size);
    gtk_render_focus(context, surface.cairo(), 0, 0, size.width(), size.height());
    return surface.GetAveragePixelValue(true);
}

GdkRGBA GetSelectionBgColor(const std::string& css_selector) {
    auto context = GetStyleContextFromCss(css_selector);
    return GetBgColorFromStyleContext(std::move(context));
}



bool ContextHasClass(GtkCssContext context, const std::string& style_class) {
    bool has_class = gtk_style_context_has_class(context, style_class.c_str());
    if (!GtkCheckVersion(4)) {
        has_class |= gtk_widget_path_iter_has_class(
                    gtk_style_context_get_path(context), -1, style_class.c_str());
    }
    return has_class;
}

GdkRGBA GetSeparatorColor(const std::string& css_selector) {
    auto context = GetStyleContextFromCss(css_selector);
    bool horizontal = ContextHasClass(context, "horizontal");

    int w = 1, h = 1;
    if (GtkCheckVersion(4)) {
        auto size = GetSeparatorSize(horizontal);
        w = size.width();
        h = size.height();
    } else {
        gtk_style_context_get(context, gtk_style_context_get_state(context), "min-width", &w,&nbsp;"min-height", &h, nullptr);
    }

    MyInset border = GtkStyleContextGetBorder(context);
    MyInset padding = GtkStyleContextGetPadding(context);

    w += border.left() + padding.left() + padding.right() + border.right();
    h += border.top() + padding.top() + padding.bottom() + border.bottom();

    if (horizontal) {
        w = 24;
        h = std::max(h, 1);
    } else {
        assert(ContextHasClass(context, "vertical"));
        h = 24;
        w = std::max(w, 1);
    }

    CairoSurface surface(MySize(w, h));
    gtk_render_background(context, surface.cairo(), 0, 0, w, h);
    gtk_render_frame(context, surface.cairo(), 0, 0, w, h);
    return surface.GetAveragePixelValue(false);
}

std::string GetGtkSettingsStringProperty(GtkSettings* settings,
                                         const gchar* prop_name) {
    GValue layout = G_VALUE_INIT;
    g_value_init(&layout, G_TYPE_STRING);
    g_object_get_property(G_OBJECT(settings), prop_name, &layout);
    assert(G_VALUE_HOLDS_STRING(&layout));
    std::string prop_value(g_value_get_string(&layout));
    g_value_unset(&layout);
    return prop_value;
}

GtkIconTheme* GetDefaultIconTheme() {
#if 0 //FIXME GTK4
    return GtkCheckVersion(4)
            ? gtk_icon_theme_get_for_display(gdk_display_get_default())
            : gtk_icon_theme_get_default();
#endif
    return gtk_icon_theme_get_default();
}

void GtkWindowDestroy(GtkWidget* widget) {
#if 0 //FIXME GTK4
    if (GtkCheckVersion(4))
        gtk_window_destroy(GTK_WINDOW(widget));
#endif
    gtk_widget_destroy(widget);
}

GtkWidget* GetDummyWindow() {
    static GtkWidget* window = CreateDummyWindow();
    return window;
}

MySize GetSeparatorSize(bool horizontal) {
    auto widget = TakeGObject(gtk_separator_new(
                                  horizontal ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL));
    GtkRequisition natural_size;
    gtk_widget_get_preferred_size(widget, nullptr, &natural_size);
    return {natural_size.width, natural_size.height};
}

static float g_deviceScaleFactor =  1.0f;

void SetDeviceScaleFactor(float scaleFactor) {
    g_deviceScaleFactor = scaleFactor;
}

float GetDeviceScaleFactor() {
    return g_deviceScaleFactor;
}


}  // namespace gtk

Messung
CHZG
87999794

¤ Dauer der Verarbeitung: 0.13 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.