X-Git-Url: https://git.sur5r.net/?p=i3%2Fi3;a=blobdiff_plain;f=src%2Fscratchpad.c;h=16e26ceebe32b0964380b039e8a710fabe9274c8;hp=b00d7f616e88b24f63047ec8735178cc4807035e;hb=d660c4bcffeb56d8a967bf9de747b8fafa691445;hpb=51728bab77210a1050f11df0f0e27b3b88dc6674 diff --git a/src/scratchpad.c b/src/scratchpad.c index b00d7f61..16e26cee 100644 --- a/src/scratchpad.c +++ b/src/scratchpad.c @@ -1,3 +1,5 @@ +#undef I3__FILE__ +#define I3__FILE__ "scratchpad.c" /* * vim:ts=4:sw=4:expandtab * @@ -58,7 +60,8 @@ void scratchpad_move(Con *con) { /* 4: Fix focus. Normally, when moving a window to a different output, the * destination output gets focused. In this case, we don’t want that. */ - con_focus(focus_next); + if (con_get_workspace(focus_next) == con_get_workspace(focused)) + con_focus(focus_next); } /* @@ -75,6 +78,16 @@ void scratchpad_show(Con *con) { Con *__i3_scratch = workspace_get("__i3_scratch", NULL); Con *floating; + /* If the current con or any of its parents are in fullscreen mode, we + * first need to disable it before showing the scratchpad con. */ + Con *fs = focused; + while (fs && fs->fullscreen_mode == CF_NONE) + fs = fs->parent; + + if (fs->type != CT_WORKSPACE) { + con_toggle_fullscreen(focused, CF_OUTPUT); + } + /* If this was 'scratchpad show' without criteria, we check if the * currently focused window is a scratchpad window and should be hidden * again. */ @@ -88,16 +101,21 @@ void scratchpad_show(Con *con) { /* If this was 'scratchpad show' with criteria, we check if it matches a * currently visible scratchpad window and hide it. */ + Con *active = con_get_workspace(focused); + Con *current = con_get_workspace(con); if (con && (floating = con_inside_floating(con)) && floating->scratchpad_state != SCRATCHPAD_NONE && - con_get_workspace(con) != __i3_scratch) { - DLOG("Window is a scratchpad window, hiding it.\n"); - scratchpad_move(con); - return; + current != __i3_scratch) { + /* If scratchpad window is on the active workspace, then we should hide + * it, otherwise we should move it to the active workspace. */ + if (current == active) { + DLOG("Window is a scratchpad window, hiding it.\n"); + scratchpad_move(con); + return; + } } - Con *ws = con_get_workspace(focused); if (con == NULL) { /* Use the container on __i3_scratch which is highest in the focus * stack. When moving windows to __i3_scratch, they get inserted at the @@ -112,7 +130,7 @@ void scratchpad_show(Con *con) { } /* 1: Move the window from __i3_scratch to the current workspace. */ - con_move_to_workspace(con, ws, true, false); + con_move_to_workspace(con, active, true, false); /* 2: Adjust the size if this window was not adjusted yet. */ if (con->scratchpad_state == SCRATCHPAD_FRESH) { @@ -127,5 +145,75 @@ void scratchpad_show(Con *con) { con->scratchpad_state = SCRATCHPAD_CHANGED; } + /* Activate active workspace if window is from another workspace to ensure + * proper focus. */ + if (current != active) { + workspace_show(active); + } + con_focus(con_descend_focused(con)); } + +/* + * Greatest common divisor, implemented only for the least common multiple + * below. + * + */ +static int _gcd(const int m, const int n) { + if (n == 0) + return m; + return _gcd(n, (m % n)); +} + +/* + * Least common multiple. We use it to determine the (ideally not too large) + * resolution for the __i3 pseudo-output on which the scratchpad is on (see + * below). We could just multiply the resolutions, but for some pathetic cases + * (many outputs), using the LCM will achieve better results. + * + * Man, when you were learning about these two algorithms for the first time, + * did you think you’d ever need them in a real-world software project of + * yours? I certainly didn’t until now. :-D + * + */ +static int _lcm(const int m, const int n) { + const int o = _gcd(m, n); + return ((m * n) / o); +} + +/* + * When starting i3 initially (and after each change to the connected outputs), + * this function fixes the resolution of the __i3 pseudo-output. When that + * resolution is not set to a function which shares a common divisor with every + * active output’s resolution, floating point calculation errors will lead to + * the scratchpad window moving when shown repeatedly. + * + */ +void scratchpad_fix_resolution(void) { + Con *__i3_scratch = workspace_get("__i3_scratch", NULL); + Con *__i3_output = con_get_output(__i3_scratch); + DLOG("Current resolution: (%d, %d) %d x %d\n", + __i3_output->rect.x, __i3_output->rect.y, + __i3_output->rect.width, __i3_output->rect.height); + Con *output; + int new_width = -1, + new_height = -1; + TAILQ_FOREACH(output, &(croot->nodes_head), nodes) { + if (output == __i3_output) + continue; + DLOG("output %s's resolution: (%d, %d) %d x %d\n", + output->name, output->rect.x, output->rect.y, + output->rect.width, output->rect.height); + if (new_width == -1) { + new_width = output->rect.width; + new_height = output->rect.height; + } else { + new_width = _lcm(new_width, output->rect.width); + new_height = _lcm(new_height, output->rect.height); + } + } + DLOG("new width = %d, new height = %d\n", + new_width, new_height); + __i3_output->rect.width = new_width; + __i3_output->rect.height = new_height; +}