Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Double Borders/frames? #738

Open
Barbaross93 opened this issue Jul 17, 2020 · 34 comments
Open

Double Borders/frames? #738

Barbaross93 opened this issue Jul 17, 2020 · 34 comments
Assignees
Labels

Comments

@Barbaross93
Copy link

I apologize as this isn't an issue ; more of a question/request. I was wondering if its possible to setup double borders around the notification window? I'm aware of the settings allowing for one frame color, but I haven't found a way to set two frame colors. I currently use a tool called chwb2 from wmutils (https://github.com/wmutils/opt) to set double borders on normal windows, however, it works by accepting a window id. At least in bspwm, I can't seem to get a window id of the notification window (xprop doesn't return any wid).

Installation info

  • Version: v1.4.1-118-g0de8610
  • Install type: dunst-git from AUR
  • Distro and version: Arch Linux
@Iss-in
Copy link

Iss-in commented Jul 22, 2020

you can edit the source code , editing the render_background function in draw.c and learning a bit of cairo for how to will do it, should be a rather easy addition

@tsipinakis
Copy link
Member

I'm not sure exactly what you mean by double border (a screenshot would help). Dunst uses an override redirect window so I'm not sure how much luck you'd have with trying to mess with it.

@Barbaross93
Copy link
Author

1595506336

Hopefully this make it a little clearer; My windows have two border colors, a lighter green/grey inner border (depending on whether the window is focused or not) and a dark outer color. If I can't get window properties on dunst's windows then editing the source code is probably my only hope :(

@Barbaross93
Copy link
Author

So, I have zero background in C and therefore have no clue what I'm doing, but I tried looking at and studied the function @kushraj suggested. Here are my edits to it (which I 100% fully expect to not work):

static cairo_surface_t *render_background(cairo_surface_t *srf,
                                          struct colored_layout *cl,
                                          struct colored_layout *cl_next,
                                          int y,
                                          int width,
                                          int height,
                                          int corner_radius,
                                          bool first,
					  bool second,
					  bool penultimate,
                                          bool last,
                                          int *ret_width)
{
        int x = 0;
        int radius_int = corner_radius;

        cairo_t *c = cairo_create(srf);

        /* stroke area doesn't intersect with main area */
        cairo_set_fill_rule(c, CAIRO_FILL_RULE_EVEN_ODD);

        /* for correct combination of adjacent areas */
        cairo_set_operator(c, CAIRO_OPERATOR_ADD);

        if (first)
                height += settings.frame_width;
	if (second)
		height += settings.frame_width_outer;
	if (penultimate)
		height += settings.frame_width;
        if (last)
                height += settings.frame_width_outer;
        else
                height += settings.separator_height;

        draw_rounded_rect(c, x, y, width, height, corner_radius, first, last);

        /* adding frame */
        x += settings.frame_width;
        if (first) {
                y += settings.frame_width;
                height -= settings.frame_width;
        }

        width -= 2 * settings.frame_width;

	x += settings.frame_width_outer;
	if (second) {
		y += settings.frame_width;
		height -= settings.frame_width_outer;
	}

	width -= 2 * settings.frame_width_outer;

	if (penultimate) {
		height -= settings.frame_width;
	else
		height -= settings.separator_height;
	}

        if (last)
                height -= settings.frame_width_outer;
        else
                height -= settings.separator_height;

        radius_int = frame_internal_radius(corner_radius, settings.frame_width, height);
	radius_int = frame_internal_radius(corner_radius, settings.frame_width_outer, height);

        draw_rounded_rect(c, x, y, width, height, radius_int, first, last);
        cairo_set_source_rgba(c, cl->frame_outer.r, cl->frame_outer.g, cl->frame_outer.b, cl->frame_outer.a);
        cairo_fill(c);

        draw_rounded_rect(c, x, y, width, height, radius_int, first, last);
        cairo_set_source_rgba(c, cl->frame.r, cl->frame.g, cl->frame.b, cl->frame.a);
        cairo_fill(c);

        draw_rounded_rect(c, x, y, width, height, radius_int, first, last);
        cairo_set_source_rgba(c, cl->bg.r, cl->bg.g, cl->bg.b, cl->bg.a);
        cairo_fill(c);

        cairo_set_operator(c, CAIRO_OPERATOR_SOURCE);

        if (   settings.sep_color.type != SEP_FRAME
            && settings.separator_height > 0
            && !last) {
                struct color sep_color = layout_get_sepcolor(cl, cl_next);
                cairo_set_source_rgba(c, sep_color.r, sep_color.g, sep_color.b, sep_color.a);

                cairo_rectangle(c, settings.frame_width, y + height, width, settings.separator_height);

                cairo_fill(c);
        }

        cairo_destroy(c);

        if (ret_width)
                *ret_width = width;

        return cairo_surface_create_for_rectangle(srf, x, y, width, height);
}

if either @kushraj, @tsipinakis, or anyone who stumbles upon this issue would be willing to guide me through this, I'll try to implement it. If you'd prefer I'd do this in the form of a PR, let me know. I didn't think it would be worth it at this point since I'm 100% certain that this won't work in its current state.

@fwsmit
Copy link
Member

fwsmit commented Feb 12, 2021

Have you tried running it? It's not that hard to build Dunst.
I don't think we'll accept it as a PR now, since the drawing code is already quite messy, and you'll likely only want double borders if all windows have double borders.
But I'm happy to help you a bit too get it done :).

@Barbaross93
Copy link
Author

Barbaross93 commented Feb 12, 2021

Well, based on your most excellent suggestion @fwsmit, simply compiling dunst gave me super helpful messages of where I needed to correct things. I spent a few hours and realized that the necessary changes are much simpler than I thought. All I had to do was define an outer width frame and simply add/subtract it to where frame_width were called. However, the thing I'm stuck on is how do I color just the outer frame? I'm able to compile what I have, but I get segfaults whenever a notification is sent. I tried adding a colors.frame_outer to notification.h struct notification_colors after adding struct color frame_outer to struct colored_layout in draw.c and cl->frame_outer = string_to_color(n->colors.frame_outer); on line 339 in draw.c. I'll see if I can make a fork and push a commit there to make this clearer

EDIT:
Here's my fork: https://github.com/Barbarossa93/dunst
Any ideas @fwsmit?

@Iss-in
Copy link

Iss-in commented Feb 12, 2021

yeah, is it really necessary to make a commit ? I actually did the same thing some time before, its somewhat messy implementation so I just left it separate. could send you that code part if you want it ?

@Barbaross93
Copy link
Author

I just thought a commit would make it easier to understand what I was describing. I didn't feel like I was making much sense... but I guess that's probably because I don't fully understand what I'm doing?

In any case, yeah, I'd love to see what you have @kushraj

@Iss-in
Copy link

Iss-in commented Feb 12, 2021

sure, I will ping you tomorrow

@Iss-in
Copy link

Iss-in commented Feb 13, 2021

here, you can use this version

@fwsmit fwsmit added the Feature label Feb 13, 2021
@Barbaross93
Copy link
Author

Barbaross93 commented Feb 13, 2021

Thanks @kushraj! That was a huge help. My code no longer seg faults, and I feel I'm incredibly close to the end product; The problems I have now are that the inner border color isn't quite right. It's a bit lighter than it should be. Additionally, I have the inner border running in between the notifications when ideally they wouldn't be there at all. Could someone take a look at my latest changes over at my fork? I've spent hours and can't make any further headway with this. I think if there's a way to tell cairo to overwrite rather than add colors that would solve the first problem; secondly, if I can create a proper second frame, I shouldn't see the inner borders running between the notifications.

EDIT:
Wow, just occurred to me to change the cairo operator. The colors are now how they are suppose to be! The separator is still not applied correctly, and the inner frame color runs between notifications, but at least the colors are right. Still would appreciate some help here

@Iss-in
Copy link

Iss-in commented Feb 14, 2021

Actually my code works just fine ( for dual borders ), you will have to use some new options in config to setup the borders properly.
Also you might want to clone and build the code again, I edited it a bit

I made some other changes too, frame is now for every notification separately and inner border is now of same color as average color of icon which you can toggle off in config file

I shouldn't see the inner borders running between the notifications

are you talking about separator color ? you can set that to transparent

@Barbaross93
Copy link
Author

Barbaross93 commented Feb 14, 2021

I think you misunderstood @kushraj, I'm not using your fork. I'm continuing to improve mine. While your fork works indeed, I don't quite like your implementation. Even with your latest changes, I don't see a separator between the notifications, I see a small gap. You also have the double borders running around each notification. What I want is to have it run around the entire notification window. Here's a screenshot of yours:
1613307450
Here's a screenshot of mine:
1613307513
The problem I have with mine currently is that the separator is overlapped by the inner frame. I can't figure out how to make it draw as a window wide border rather than a per notification border

@Iss-in
Copy link

Iss-in commented Feb 14, 2021

oh yeah, I actually wanted all my notifications separately with individual borders, that's exactly what I implemented.

Because of picom, shadow is applied to entire window making them seem connected. Not a problem for me as I'm using sway, ( no shadows) so it looks good in mine.

guess, I can take a look at your fork

@Barbaross93
Copy link
Author

I'd appreciate it if you would :)

@fwsmit
Copy link
Member

fwsmit commented Feb 14, 2021

An easy way to make sure you don't draw the border in between notifications is to only draw the left and right line, and only if it's the first or last notification, draw the top or bottom line. That's the same way rounded corners are drawn.
Notice that a bool is passed you can used to see if it's the first or last notification:

static cairo_surface_t *render_background(cairo_surface_t *srf,
                                          struct colored_layout *cl,
                                          struct colored_layout *cl_next,
                                          int y,
                                          int width,
                                          int height,
                                          int corner_radius,
                                          bool first,
                                          bool last,
                                          int *ret_width)

@Barbaross93
Copy link
Author

Hmm, I thought my border drawing logic was ok. I thought my problem was the painting bit. I'll take another stab at the border drawing section. Should I maybe incorporate the painting logic into the drawing section?

@fwsmit
Copy link
Member

fwsmit commented Feb 14, 2021

I'm not sure what you mean by painting logic. What may be causing you issue is that draw_rounded_rect is drawing a filled in rectangle of that color. On line 612 you draw that rectangle with yellow color. I suspect that one isn't drawn over by something else, leaving those lines there. I'm not very sure though

@Barbaross93
Copy link
Author

Thanks for the hint @fwsmit, I think I finally figured it out!!
1613364862
I think I need to do some more strenuous testing; as I'm pretty sure dynamic width won't work since I didn't factor in the outer border width, but for the moment, this should work! I plan to do some more cleanup and renaming the options to something more reasonable (like @kushraj's setting naming) and I think that should be it!

@Barbaross93
Copy link
Author

Barbaross93 commented Feb 15, 2021

Welp, the problem now is that if the separator height is significantly larger than the inner frame border, there's a gap on the sides for the inner frame. Not sure how to proceed =/

EDIT:
Nevermind, turned out to be a simple fix!

@fwsmit
Copy link
Member

fwsmit commented Feb 15, 2021

Just to be clear, we won't accept this feature in dunst right now. It's probably too specific for it to be worth the added complexity. If more users are interested in this feature being added to Dunst, please comment.
Good to hear that your fork is working though

@aonphleacs
Copy link

I'm just going to comment here to say... this feature seems great, especially for the ricing community. It certainly leads me to wonder if providing an input for a variable to determine the number of borders would be simple enough. Then when someone comes along asking about three borders it would already be possible.

@fwsmit
Copy link
Member

fwsmit commented Apr 29, 2021

And how would you select the color for the borders then?

@Barbaross93
Copy link
Author

While I think it is a cool idea, I do see this adding a bit more in terms of code complexity. Since that's what @fwsmit is trying to avoid, I'm not sure how feasible this would be.

In terms of the configuration, maybe specify a list of width and colors based on a configured number of frames? So something like:

number_of_frames = 3
frame_width = 2,6,1
frame_color = '#000000,#ffffff,#cccccc'

No idea how complicated this would be to implement, but again, I do like it.

@fwsmit
Copy link
Member

fwsmit commented Apr 29, 2021

Yeah I though something like that as well. It wouldn't be terribly hard to implement.
The problem is that I feel like an arbitrary number of border seems like such a niche feature, whole still being pretty complicated.
If you want to see multiple borders I would suggest using @Barbarossa93's fork. You can even contribute a more than 2 borders patch there.

@Barbaross93
Copy link
Author

Yeah, I'd be more than happy for PRs at my fork for this sort of thing. I think it'd require a bit of a rewrite of what I currently have, but if someone wants to implement it, than by all means go for it.

Also, it seems like a niche feature... until more people know about it ;)

@aonphleacs
Copy link

I have literally zero experience with C (not that that's an excuse) and almost none with git (also, not an excuse) but when I have some time I'll try to get my hands dirty on this :3

I guess from my perspective, doing something like this isn't about added complexity - it's about added modularity (which, of course, usually comes with more lines of code). But, hey, that's why forks exist I suppose!

@FrenzyExists
Copy link

It be great if its merged, the ricing comunity will love it

@lokesh-krishna
Copy link

Just wanted to pitch in that this would indeed be an awesome feature for the ricing community!

@jobcmax
Copy link

jobcmax commented Apr 14, 2023

i am really really interested in this feature, would be cool for my 2 border theme on bspwm

@The-Sound
Copy link

I wouldn't mind having a little bit of a tool that we could use along the lines of css statements like border-style: double. Sadly I lack the knowledge to implement it so I can just ask. Apologies.

@bynect
Copy link
Member

bynect commented Feb 21, 2024

Is it me or the double borders is just a border offset inside the background? Maybe this solution can be generalized with a border_offset of some sort?

@fwsmit
Copy link
Member

fwsmit commented Feb 21, 2024

For a double border you need an inset border and and outsite border

@bynect
Copy link
Member

bynect commented Feb 21, 2024

For a double border you need an inset border and and outsite border

in general, yes, but in this case it seems like the outer border and the inner color are the same (to achieve the offset look)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

10 participants