<commit_before>/* copyright 2013 <NAME> and contributors (see LICENSE for licensing information) */
#include <math.h>
#include <sys/time.h>
#include <ctype.h>
#include <assert.h>
#include <locale.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/X.h>
#include <X11/Xatom.h>
#include <pango/pangocairo.h>
#include <cairo-xlib.h>

#include "x.h"
#include "utils.h"
#include "dunst.h"
#include "settings.h"
#include "notification.h"

#define WIDTH 400
#define HEIGHT 400

xctx_t xctx;
bool dunst_grab_errored = false;

typedef struct _cairo_ctx {
        cairo_status_t status;
        cairo_surface_t *surface;
        PangoFontDescription *desc;
} cairo_ctx_t;

typedef struct _colored_layout {
        PangoLayout *l;
        color_t fg;
        color_t bg;
        char *text;
        PangoAttrList *attr;
} colored_layout;

cairo_ctx_t cairo_ctx;

static color_t frame_color;

static void x_shortcut_setup_error_handler(void);
static int x_shortcut_tear_down_error_handler(void);
static void x_win_move(int width, int height);


static color_t x_color_hex_to_double(int hexValue)
{
        color_t color;
        color.r = ((hexValue >> 16) & 0xFF) / 255.0;
        color.g = ((hexValue >> 8) & 0xFF) / 255.0;
        color.b = ((hexValue) & 0xFF) / 255.0;

  return color;
}

static color_t x_string_to_color_t(const char *str)
{
        char *end;
        long int val = strtol(str+1, &end, 16);
        if (*end != '\0' && *(end+1) != '\0') {
                printf("WARNING: Invalid color string: \"%s\"\n", str);
        }

        return x_color_hex_to_double(val);
}

color_t calculate_foreground_color(color_t bg)
{
        double c_delta = 0.1;
        color_t color = bg;

        /* do we need to darken or brighten the colors? */
        bool darken = (bg.r + bg.g + bg.b) / 3 > 0.5;

        if (darken) {
                if (color.r - c_delta < 0)
                        color.r = 0;
                else
                        color.r -= c_delta;
                if (color.g - c_delta < 0)
                        color.g = 0;
                else
                        color.g -= c_delta;
                if (color.b - c_delta < 0)
                        color.b = 0;
                else
                        color.b -= c_delta;
        } else {
                if (color.r + c_delta > 1)
                        color.r = 1;
                else
                        color.r += c_delta;
                if (color.g + c_delta > 1)
                        color.g = 1;
                else
                        color.g += c_delta;
                if (color.b + c_delta > 1)
                        color.g = 1;
                else
                        color.g += c_delta;
        }

        return color;
}


static color_t x_get_separator_color(color_t fg, color_t bg)
{
        switch (settings.sep_color) {
                case FRAME:
                        return x_string_to_color_t(settings.frame_color);
                case CUSTOM:
                        return x_string_to_color_t(settings.sep_custom_color_str);
                case FOREGROUND:
                        return fg;
                case AUTO:
                        return calculate_foreground_color(bg);

        }
}

void x_cairo_setup(void)
{
        cairo_ctx.surface = cairo_xlib_surface_create(xctx.dpy,
                        xctx.win, DefaultVisual(xctx.dpy, 0), WIDTH, HEIGHT);

        cairo_ctx.desc = pango_font_description_from_string(settings.font);

        frame_color = x_string_to_color_t(settings.frame_color);
}

void r_setup_pango_layout(PangoLayout *layout, int width)
{
        pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
        pango_layout_set_width(layout, width * PANGO_SCALE);
        pango_layout_set_font_description(layout, cairo_ctx.desc);
        pango_layout_set_spacing(layout, settings.line_height * PANGO_SCALE);

        PangoAlignment align;
        switch (settings.align) {
                case left:
                        align = PANGO_ALIGN_LEFT;
                        break;
                case center:
                        align = PANGO_ALIGN_CENTER;
                        break;
                case right:
                        align = PANGO_ALIGN_RIGHT;
                        break;
        }
        pango_layout_set_alignment(layout, align);

}

static void free_colored_layout(void *data)
{
        colored_layout *cl = data;
        g_object_unref(cl->l);
        g_free(cl->text);
}

static int calculate_width(void)
{
        screen_info scr;
        x_screen_info(&scr);
        if (xctx.geometry.mask & WidthValue && xctx.geometry.w == 0) {
                /* dynamic width */
                return 0;
        } else if (xctx.geometry.mask & WidthValue) {
                /* fixed width */
                if (xctx.geometry.negative_width) {
                        return scr.dim.w - xctx.geometry.w;
                } else {
                        return xctx.geometry.w;
                }
        } else {
                /* across the screen */
                return scr.dim.w;
        }
}

static colored_layout *r_init_shared(cairo_t *c, notification *n)
{
        colored_layout *cl = malloc(sizeof(colored_layout));
        cl->l = pango_cairo_create_layout(c);


        cl->fg = x_string_to_color_t(n->color_strings[ColFG]);
        cl->bg = x_string_to_color_t(n->color_strings[ColBG]);

        int width = calculate_width();
        if (xctx.geometry.w > 0) {
                width = xctx.geometry.w - 2 * settings.h_padding;
                width -= 2 * settings.frame_width;
                r_setup_pango_layout(cl->l, width);
        } else {
                r_setup_pango_layout(cl->l, -1);<commit_msg>ellipsize when !word_wrap<commit_after>/* copyright 2013 <NAME> and contributors (see LICENSE for licensing information) */
#include <math.h>
#include <sys/time.h>
#include <ctype.h>
#include <assert.h>
#include <locale.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/X.h>
#include <X11/Xatom.h>
#include <pango/pangocairo.h>
#include <cairo-xlib.h>

#include "x.h"
#include "utils.h"
#include "dunst.h"
#include "settings.h"
#include "notification.h"

#define WIDTH 400
#define HEIGHT 400

xctx_t xctx;
bool dunst_grab_errored = false;

typedef struct _cairo_ctx {
        cairo_status_t status;
        cairo_surface_t *surface;
        PangoFontDescription *desc;
} cairo_ctx_t;

typedef struct _colored_layout {
        PangoLayout *l;
        color_t fg;
        color_t bg;
        char *text;
        PangoAttrList *attr;
} colored_layout;

cairo_ctx_t cairo_ctx;

static color_t frame_color;

static void x_shortcut_setup_error_handler(void);
static int x_shortcut_tear_down_error_handler(void);
static void x_win_move(int width, int height);


static color_t x_color_hex_to_double(int hexValue)
{
        color_t color;
        color.r = ((hexValue >> 16) & 0xFF) / 255.0;
        color.g = ((hexValue >> 8) & 0xFF) / 255.0;
        color.b = ((hexValue) & 0xFF) / 255.0;

  return color;
}

static color_t x_string_to_color_t(const char *str)
{
        char *end;
        long int val = strtol(str+1, &end, 16);
        if (*end != '\0' && *(end+1) != '\0') {
                printf("WARNING: Invalid color string: \"%s\"\n", str);
        }

        return x_color_hex_to_double(val);
}

color_t calculate_foreground_color(color_t bg)
{
        double c_delta = 0.1;
        color_t color = bg;

        /* do we need to darken or brighten the colors? */
        bool darken = (bg.r + bg.g + bg.b) / 3 > 0.5;

        if (darken) {
                if (color.r - c_delta < 0)
                        color.r = 0;
                else
                        color.r -= c_delta;
                if (color.g - c_delta < 0)
                        color.g = 0;
                else
                        color.g -= c_delta;
                if (color.b - c_delta < 0)
                        color.b = 0;
                else
                        color.b -= c_delta;
        } else {
                if (color.r + c_delta > 1)
                        color.r = 1;
                else
                        color.r += c_delta;
                if (color.g + c_delta > 1)
                        color.g = 1;
                else
                        color.g += c_delta;
                if (color.b + c_delta > 1)
                        color.g = 1;
                else
                        color.g += c_delta;
        }

        return color;
}


static color_t x_get_separator_color(color_t fg, color_t bg)
{
        switch (settings.sep_color) {
                case FRAME:
                        return x_string_to_color_t(settings.frame_color);
                case CUSTOM:
                        return x_string_to_color_t(settings.sep_custom_color_str);
                case FOREGROUND:
                        return fg;
                case AUTO:
                        return calculate_foreground_color(bg);

        }
}

void x_cairo_setup(void)
{
        cairo_ctx.surface = cairo_xlib_surface_create(xctx.dpy,
                        xctx.win, DefaultVisual(xctx.dpy, 0), WIDTH, HEIGHT);

        cairo_ctx.desc = pango_font_description_from_string(settings.font);

        frame_color = x_string_to_color_t(settings.frame_color);
}

void r_setup_pango_layout(PangoLayout *layout, int width)
{
        pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
        pango_layout_set_width(layout, width * PANGO_SCALE);
        pango_layout_set_font_description(layout, cairo_ctx.desc);
        pango_layout_set_spacing(layout, settings.line_height * PANGO_SCALE);

        PangoAlignment align;
        switch (settings.align) {
                case left:
                        align = PANGO_ALIGN_LEFT;
                        break;
                case center:
                        align = PANGO_ALIGN_CENTER;
                        break;
                case right:
                        align = PANGO_ALIGN_RIGHT;
                        break;
        }
        pango_layout_set_alignment(layout, align);

}

static void free_colored_layout(void *data)
{
        colored_layout *cl = data;
        g_object_unref(cl->l);
        g_free(cl->text);
}

static int calculate_width(void)
{
        screen_info scr;
        x_screen_info(&scr);
        if (xctx.geometry.mask & WidthValue && xctx.geometry.w == 0) {
                /* dynamic width */
                return 0;
        } else if (xctx.geometry.mask & WidthValue) {
                /* fixed width */
                if (xctx.geometry.negative_width) {
                        return scr.dim.w - xctx.geometry.w;
                } else {
                        return xctx.geometry.w;
                }
        } else {
                /* across the screen */
                return scr.dim.w;
        }
}

static colored_layout *r_init_shared(cairo_t *c, notification *n)
{
        colored_layout *cl = malloc(sizeof(colored_layout));
        cl->l = pango_cairo_create_layout(c);

        if (!settings.word_wrap) {
                pango_layout_set_ellipsize(cl->l, PANGO_ELLIPSIZE_MIDDLE);
        }


        cl->fg = x_string_to_color_t(n->color_strings[ColFG]);
        cl->bg = x_string_to_color_t(n->color_strings[ColBG]);

        int width = calculate_width();
        if (xctx.geometry.w > 0) {
                width = xctx.geometry.w - 2 * settings.h_padding;
                width -= 2 * settings.frame_width;
                r_setup_pango_layout(cl->l, width);
        } else {
                r_setup_pango_layout(cl->l, -1);
{'fraction_non_alphanumeric': 0.10227369496721452, 'fraction_numerical': 0.01090011070424934, 'mean_word_length': 1.624944121591417, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 72, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3963442', 'n_tokens_mistral': 3966, 'n_tokens_neox': 3675, 'n_words': 775}