ssokolow / quicktile

Adds window-tiling hotkeys to any X11 desktop. (An analogue to WinSplit Revolution for people who don't want to use Compiz Grid)
https://ssokolow.com/quicktile/
GNU General Public License v2.0
869 stars 78 forks source link

4K screen adaptation #60

Open boussou opened 8 years ago

boussou commented 8 years ago

Hi, I would like to patch the code to make the most of my 4K screen.

What I need is get rid of that 0.5 factor but insteal allow 5 to 7 vertical columns and be able to cycle through them.

The problem: I need to learn Python before ;-( I have seen those gravities enums, the POSITIONS array. Can someone help me doing the proper change?

ssokolow commented 8 years ago

Hi. Sorry for not providing a GUI to make that easy. It's been on my TODO list for ages but more important things (typically university-related) keep coming up. (At the moment, I'm working on my degree project.)

QuickTile should be able to do any layout you want, but in order to help you, I'll need you to explain exactly what kind of layout you want to generate, since there are multiple ways to have a 5-7 column layout mapped to commands.

However, I can give you a quick overview of how that code works without needing clarification from you.

Start with this bit:

col, gv = 1.0 / 3, GravityLayout()

# TODO: Figure out how best to put this in the config file.
POSITIONS = {
    'middle': [gv(x, 1, 'middle') for x in (1.0, col, col * 2)],
}  #: command-to-position mappings for L{cycle_dimensions}

for grav in ('top', 'bottom'):
    POSITIONS[grav] = [gv(x, 0.5, grav) for x in (1.0, col, col * 2)]
for grav in ('left', 'right'):
    POSITIONS[grav] = [gv(x, 1, grav) for x in (0.5, col, col * 2)]
for grav in ('top-left', 'top-right', 'bottom-left', 'bottom-right'):
    POSITIONS[grav] = [gv(x, 0.5, grav) for x in (0.5, col, col * 2)]

If you paste this in below it and run quicktile...

import pprint
pprint.pprint(POSITIONS)

...you'll see that it's a compact, easy-to-adjust way to generate this table:

POSITIONS = {
 'bottom': [(0.0, 0.5, 1.0, 0.5),
            (0.33333333333333337, 0.5, 0.3333333333333333, 0.5),
            (0.16666666666666669, 0.5, 0.6666666666666666, 0.5)],
 'bottom-left': [(0.0, 0.5, 0.5, 0.5),
                 (0.0, 0.5, 0.3333333333333333, 0.5),
                 (0.0, 0.5, 0.6666666666666666, 0.5)],
 'bottom-right': [(0.5, 0.5, 0.5, 0.5),
                  (0.6666666666666667, 0.5, 0.3333333333333333, 0.5),
                  (0.33333333333333337, 0.5, 0.6666666666666666, 0.5)],
 'left': [(0.0, 0.0, 0.5, 1),
          (0.0, 0.0, 0.3333333333333333, 1),
          (0.0, 0.0, 0.6666666666666666, 1)],
 'middle': [(0.0, 0.0, 1.0, 1),
            (0.33333333333333337, 0.0, 0.3333333333333333, 1),
            (0.16666666666666669, 0.0, 0.6666666666666666, 1)],
 'right': [(0.5, 0.0, 0.5, 1),
           (0.6666666666666667, 0.0, 0.3333333333333333, 1),
           (0.33333333333333337, 0.0, 0.6666666666666666, 1)],
 'top': [(0.0, 0.0, 1.0, 0.5),
         (0.33333333333333337, 0.0, 0.3333333333333333, 0.5),
         (0.16666666666666669, 0.0, 0.6666666666666666, 0.5)],
 'top-left': [(0.0, 0.0, 0.5, 0.5),
              (0.0, 0.0, 0.3333333333333333, 0.5),
              (0.0, 0.0, 0.6666666666666666, 0.5)],
 'top-right': [(0.5, 0.0, 0.5, 0.5),
               (0.6666666666666667, 0.0, 0.3333333333333333, 0.5),
               (0.33333333333333337, 0.0, 0.6666666666666666, 0.5)]}

That dict (associative array/hash/map/whatever term you may know) maps commands like bottom-left to lists of positions to cycle through if the key is tapped repeatedly.

Each position tuple takes the form (x, y, width, height) in the form of values between 0 and 1. (eg. (0.0, 0.5, 1.0, 0.5) from the bottom section means (left, 50% wide, bottom, 50% tall))

GravityHelper just abstracts away the math for positioning a window using a point other than its top-left corner. For example, if you look at the second bottom position, it's (0.33333333333333337, 0.5, 0.3333333333333333, 0.5). That was generated by gv(col, 0.5, 'bottom') where col = 1.0 / 3. GravityHelper did the hard work translating between intuitive coordinates and the "always top-left corner" coordinates the window system expects.

Once you've got commands that do what you want, then you can edit your ~/.config/quicktile.cfg to assign keys to them.

boussou commented 8 years ago

Awesome ! Even if I don't know the langage, it is pretty clear (besides I am a programmer ;-)

4K is 3840x2160, if you want to take benefit from this huge defintiion on a 28" I want to put side by side from 5 to 7 columns.

I would like to do 2 types of layouts:

btw I am not sure I understood your explanation.
you said "Each position tuple takes the form (x, y, width, height) "
and then your example " (0.0, 0.5, 1.0, 0.5) from the bottom section means (left, 50% wide, bottom, 50% tall))" .... ..50% wide???

To clarify, do (0.0, 0.5, 1.0, 0.5) means

Thanks for your quick answer.

ssokolow commented 8 years ago

Yes, your interpretation of (0.0, 0.5, 1.0, 0.5) is correct.

As for the two types of layouts you want, I'm still not sure I understand. What I was asking for (but too tired to ask for properly) was an explanation of exactly what should happen for each keybind.

As is, I don't know the answers to questions like: "Do you want to be able to put more than three windows side-by-side? If so, how do you want to deal with the fact that the numeric keypad doesn't have that many columns?"

boussou commented 8 years ago

Ah, easy answer, I use only laptops - no keypad ;-)

so my idea is to use the top number keys. (or Fx keys maybe?)

senorsmile commented 8 years ago

(a possible recommendation... please ignore if not helpful as I do not yet have a 4k display) One of the things that I do is change the binding from num keys to the keys:

u i o j k l m , .

This allows me to have the same keys on a laptop without a number pad as I do on a regular keyboard. This could easily be extended to cover more keys to have multiple possibilities on the screen. E.g.

y u i o p h j k l ; n m , . /

On Mon, Dec 21, 2015 at 4:15 PM Stephan Sokolow notifications@github.com wrote:

Yes, your interpretation of (0.0, 0.5, 1.0, 0.5) is correct.

As for the two types of layouts you want, I'm still not sure I understand. What I was asking for (but too tired to ask for properly) was an explanation of exactly what should happen for each keybind.

As is, I don't know the answers to questions like: "Do you want to be able to put more than three windows side-by-side? If so, how do you want to deal with the fact that the numeric keypad doesn't have that many columns?"

— Reply to this email directly or view it on GitHub https://github.com/ssokolow/quicktile/issues/60#issuecomment-166464517.

ssokolow commented 8 years ago

It's not so much the keys I need to know about (those are easy to set in ~/.config/quicktile.cfg) but, rather, how you want to actually map the grid.

You just clarified that you want five columns in the full sense of the word. I'll assume you also want more rows in the full sense of the word. (I currently use a 3840x1024 desktop spanned across three 19" monitors, so I rely on Ctrl+Alt+KP_Enter, but I did do the research for a 4K display. One 4K display at 49" would have size and pixel density equivalent to a 3x2 grid of 19" monitors.)

I'm starting to generalize the code for your use case and I'll have something for you to look at in a bit.

ssokolow commented 8 years ago

Ok, take a look at commit c4f13008653db1a80bb841c32d28801f0358f104. I haven't yet added an easy way to define (x, y) for more than three columns, but I've added a COLUMN_COUNT constant and editing it will adjust the number of width steps for more than 3 columns.

(COLUMN_COUNT is a constant because, currently, commands are defined before the config file is read and I wanted to push something for you to look at as quickly as reasonably possible.)

boussou commented 8 years ago

that is exactly what I wanted. Thanks! It works perfectly, I tried it with key mapping as @senorsmile suggested.

Now quicktile is the only tool around that works in large screen.

Some ideas & suggestions:

other thoughts for future releases:

I think the "grid" 3x3 should be replaced by a grid of 7x5 on wide screens.

But for my personal need, I don't need more than this change. Thanks again

ssokolow commented 8 years ago

Mapping keys to the seven columns and adding support for more rows is the "part 2" I didn't have time for now.

When I have time to move COLUMN_COUNT into quicktile.cfg and add properly generic support for defining keybinds, my plan is to generate default values based on the dimensions of the screen.

I'm not yet sure what form it will take, but once I have time to design a new, JSON-based config file format, I'll look into adding support for per-monitor tiling grids so each monitor can have the columns most suited to it.

(I also want to completely re-architect how columns and rows are handled so that I can implement keys to shrink/grow the current window's column/row and have all of the other windows adjust to match.

boussou commented 8 years ago

careful not to turn this program into a bloatware :-)

After a short time of use, finally I think that beeing able to target the other columns becomes necessary.

A suggestion: I think the grid cells should be named like in excel, A1 to G1 (7 columns of 1rst row). Then I expect there would be a lot of changes to do like ie:

Line 105:

GRAVITIES = {
    'top-left': (0.0, 0.0),
    'top': (0.5, 0.0),
    'top-right': (1.0, 0.0),
    'left': (0.0, 0.5),
    'middle': (0.5, 0.5),
    'right': (1.0, 0.5),

    'A': (1/7, 0.5),
    'B': (2/7, 0.5),
    'C': (3/7, 0.5),
    'D': (4/7, 0.5),
    'E': (5/7, 0.5),
    'F': (6/7, 0.5),
    'G': (7/7, 0.5),

below

for grav in ('A', 'B', 'C', 'D', 'E', 'F', 'G'): 
 #--> instead of "for grav in ('left', 'right'):"
     POSITIONS[grav] = [gv(width, 1, grav) for width in corner_steps]

etc. If I understand correctly reading the code, the current gravity names (eg "top-left") could coexist with other new ones (eg "A1")?

ssokolow commented 8 years ago

It doesn't work that way for two reasons:

  1. Those names like left and right are used in keybindings and the external API and predate things like gv = GravityLayout() by quite a while. If you rename them (rather than making copies), then everyone's quicktile.cfg will break, as will any scripts which use the command-line or D-Bus APIs.
  2. Note that grav is being fed into gv() as the third argument. That determines which point on the window to use as a point of reference for positioning and corresponds to one of the nine X11 window gravities. (gv() has other arguments for specifying x and y but you can omit them if they're the same as the gravity.)

Also, using Excel-style coordinates doesn't really gain anything over using integer (col, row) tuples and complicates things elsewhere because, for dynamic generation, you need routines to translate back and forth between letters and numbers.

boussou commented 8 years ago

Understood. How would you name the cells like below? (generated via http://www.tablesgenerator.com/markdown_tables)

| A1 | B1 | C1 | D1 | E1 | F1 | G1 |
|----|----|----|----|----|----|----|
| A2 | B2 | C2 | D2 | E2 | F2 | G2 |
|----|----|----|----|----|----|----|
| A3 | B3 | C3 | D3 | E3 | F3 | G3 |

Currently if I can get at least smthing like this working that would be perfect++ :

| A  | B  | C  | D  | E  | F  | G  |
|    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |

and as a dream far away a 2/3rd layout ;-)

| A1 | B1 | C1 | D1 | E1 | F1 | G1 |
|    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |
|----|----|----|----|----|----|----|
| A3 | B3 | C3 | D3 | E3 | F3 | G3 |
ssokolow commented 8 years ago

In my implementation, I'd write a new command which can take arguments and then, to tile for the cell you call B3, I'd bind a key to reposition-to-grid 2 3.

That way, I don't need to either favour one person's set of positions or flood --help with every possible position because each position is its own command.

If you don't mind your --help output being cluttered up, here is an attempt at code to define the commands you want (I'm very sleepy, so I don't have time to test it):

    ROW_COUNT = 3
    row_height = 1.0 / ROW_COUNT

    # Start the cycle at the width of one cell, rather than 50% or 100%
    cell_steps = (col_width,) + cycle_steps

    # Generate a string of letters that we can index into for column names
    colnames = ''.join((chr(x) for x in range(65, 65 + COLUMN_COUNT)))

    # Generate a command for each cell...
    for col in range(0, COLUMN_COUNT):
        for row in range(0, ROW_COUNT):
            # Each command will be named after an Excel-style cell coordinate
            POSITIONS['%s%d' % (colnames[col], row)] = [
                # gv(width, height, gravity, x, y)
                # "gravity" determines where on the window (x, y) refers to.
                gv(width, row_height * row, 'top-left', col_width * col, row_height * row)
                for width in cell_steps]
boussou commented 8 years ago

The way you state it sounds easy to understand. and regarding the help display, "less is more" ;-) So it is fine for me.

Thanks for you help, I we were near I would offer you a beer or 2 ;-)

ssokolow commented 8 years ago

chuckle I've never seen the appeal to alcohol, nor to bitter drinks, but thanks anyway.

ssokolow commented 8 years ago

I'll leave this open as a reminder to myself.

ssokolow commented 7 years ago

Just so you know, I'm finally back to working on this and I'm in the process of making the layout more adaptable.

So far, I've added a ColumnCount config key which allows you to easily change the number of columns... but there's a bug that makes the left/right edge commands still only cycle through three steps which I still need to track down.

Also, be aware that, in order to make it easier to work on QuickTile, I split it up into multiple files so you'll need to re-read the install instructions. (Don't worry. I kept the "copy into place" install option... it's just slightly different.)

ssokolow commented 7 years ago

Ok, the fix for #20 should have also fixed the cycling bug. :)

boussou commented 7 years ago

Great. I'm still using your awesome tool, i'll check that asap ;-)

ssokolow commented 4 years ago

In case you're interested in trying it out, the GTK 3 port that I'll be working toward a fix for this on is available in the gtk3_port branch now.

I still need to fix regressions #107 and #108 before it'll be at parity with the GTK+ 2 version, but it's already got much cleaner internals and a growing suite of automated tests.

Just don't use the pip3 URL from its README. That'll point to the GTK+ 2.x version until the port gets merged into master.

ssokolow commented 4 years ago

Note to Self: See also discussion on #99.

boussou commented 4 years ago

I myself don't know anything about Python, so I will wait until the setup is easy.

ssokolow commented 4 years ago

It's no more difficult than with QuickTile for GTK+ 2.x. If you're on Debian, Ubuntu, Mint, or Fedora, I can give you trivially simple instructions.

(The same instructions will be in the README and on the site once I finish the new manual.)