123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- --[[
- Licensed under GNU General Public License v2
- * (c) 2016, Luca CPZ
- * (c) 2015, unknown
- --]]
- local awful = require("awful")
- local capi = { client = client }
- local math = math
- local string = string
- local pairs = pairs
- local screen = screen
- local setmetatable = setmetatable
- -- Quake-like Dropdown application spawn
- local quake = {}
- -- If you have a rule like "awful.client.setslave" for your terminals,
- -- ensure you use an exception for QuakeDD. Otherwise, you may
- -- run into problems with focus.
- function quake:display()
- if self.followtag then self.screen = awful.screen.focused() end
- -- First, we locate the client
- local client = nil
- local i = 0
- for c in awful.client.iterate(function (c)
- -- c.name may be changed!
- return c.instance == self.name
- end)
- do
- i = i + 1
- if i == 1 then
- client = c
- else
- -- Additional matching clients, let's remove the sticky bit
- -- which may persist between awesome restarts. We don't close
- -- them as they may be valuable. They will just turn into
- -- normal clients.
- c.sticky = false
- c.ontop = false
- c.above = false
- end
- end
- if not client and not self.visible then return end
- if not client then
- -- The client does not exist, we spawn it
- local cmd = string.format("%s %s %s", self.app,
- string.format(self.argname, self.name), self.extra)
- awful.spawn(cmd, { tag = self.screen.selected_tag })
- return
- end
- -- Set geometry
- client.floating = true
- client.border_width = self.border
- client.size_hints_honor = false
- local maximized = client.maximized
- local fullscreen = client.fullscreen
- client:geometry(self.geometry[self.screen.index] or self:compute_size())
- -- Set not sticky and on top
- client.sticky = false
- client.ontop = true
- client.above = true
- client.skip_taskbar = true
- -- Additional user settings
- if self.settings then self.settings(client) end
- -- Toggle display
- if self.visible then
- client.hidden = false
- client.maximized = self.maximized
- client.fullscreen = self.fullscreen
- client:raise()
- self.last_tag = self.screen.selected_tag
- client:tags({self.screen.selected_tag})
- capi.client.focus = client
- else
- self.maximized = maximized
- self.fullscreen = fullscreen
- client.maximized = false
- client.fullscreen = false
- client.hidden = true
- local ctags = client:tags()
- for j, _ in pairs(ctags) do
- ctags[j] = nil
- end
- client:tags(ctags)
- end
- return client
- end
- function quake:compute_size()
- -- skip if we already have a geometry for this screen
- if not self.geometry[self.screen.index] then
- local geom
- if not self.overlap then
- geom = screen[self.screen.index].workarea
- else
- geom = screen[self.screen.index].geometry
- end
- local width, height = self.width, self.height
- if width <= 1 then width = math.floor(geom.width * width) - 2 * self.border end
- if height <= 1 then height = math.floor(geom.height * height) end
- local x, y
- if self.horiz == "left" then x = geom.x
- elseif self.horiz == "right" then x = geom.width + geom.x - width
- else x = geom.x + (geom.width - width)/2 end
- if self.vert == "top" then y = geom.y
- elseif self.vert == "bottom" then y = geom.height + geom.y - height
- else y = geom.y + (geom.height - height)/2 end
- self.geometry[self.screen.index] = { x = x, y = y, width = width, height = height }
- end
- return self.geometry[self.screen.index]
- end
- function quake:toggle()
- if self.followtag then self.screen = awful.screen.focused() end
- local current_tag = self.screen.selected_tag
- if current_tag and self.last_tag ~= current_tag and self.visible then
- local c=self:display()
- if c then
- c:move_to_tag(current_tag)
- end
- else
- self.visible = not self.visible
- self:display()
- end
- end
- function quake.new(conf)
- conf = conf or {}
- conf.app = conf.app or "xterm" -- application to spawn
- conf.name = conf.name or "QuakeDD" -- window name
- conf.argname = conf.argname or "-name %s" -- how to specify window name
- conf.extra = conf.extra or "" -- extra arguments
- conf.border = conf.border or 1 -- client border width
- conf.visible = conf.visible or false -- initially not visible
- conf.followtag = conf.followtag or false -- spawn on currently focused screen
- conf.overlap = conf.overlap or false -- overlap wibox
- conf.screen = conf.screen or awful.screen.focused()
- conf.settings = conf.settings
- -- If width or height <= 1 this is a proportion of the workspace
- conf.height = conf.height or 0.25 -- height
- conf.width = conf.width or 1 -- width
- conf.vert = conf.vert or "top" -- top, bottom or center
- conf.horiz = conf.horiz or "left" -- left, right or center
- conf.geometry = {} -- internal use
- conf.maximized = false
- conf.fullscreen = false
- local dropdown = setmetatable(conf, { __index = quake })
- capi.client.connect_signal("manage", function(c)
- if c.instance == dropdown.name and c.screen == dropdown.screen then
- dropdown:display()
- end
- end)
- capi.client.connect_signal("unmanage", function(c)
- if c.instance == dropdown.name and c.screen == dropdown.screen then
- dropdown.visible = false
- end
- end)
- return dropdown
- end
- return setmetatable(quake, { __call = function(_, ...) return quake.new(...) end })
|