Revert "Replace tags by workspaces"

This reverts commit 00f966ea04.

Revert "[focus] Fix bogus arguments"
This reverts commit 816b5d16bc.

Revert "[mouse] Fix bug with floating"
This reverts commit 89daa72790.

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Julien Danjou 2008-06-09 21:43:09 +02:00
parent ac1517bacb
commit 1049393840
34 changed files with 1395 additions and 1119 deletions

View File

@ -32,7 +32,7 @@ LAYOUTS += layouts/magnifier.c
LAYOUTS += layouts/magnifier.h LAYOUTS += layouts/magnifier.h
WIDGETS = WIDGETS =
WIDGETS += widgets/workspacelist.c WIDGETS += widgets/taglist.c
WIDGETS += widgets/textbox.c WIDGETS += widgets/textbox.c
WIDGETS += widgets/iconbox.c WIDGETS += widgets/iconbox.c
WIDGETS += widgets/progressbar.c WIDGETS += widgets/progressbar.c
@ -128,7 +128,7 @@ awesome_SOURCES = \
layout.c layout.h \ layout.c layout.h \
keybinding.c keybinding.h \ keybinding.c keybinding.h \
awesome.c \ awesome.c \
workspace.c workspace.h \ tag.c tag.h \
lua.c lua.h \ lua.c lua.h \
screen.c screen.h \ screen.c screen.h \
statusbar.c statusbar.h \ statusbar.c statusbar.h \

View File

@ -26,6 +26,7 @@ awesome-client reads commands from standard input.
When you pipe multiple lines into awesome-client, an empty line will flush already When you pipe multiple lines into awesome-client, an empty line will flush already
collected lines into awesome with an according immediate execution. collected lines into awesome with an according immediate execution.
SEE ALSO SEE ALSO
-------- --------
awesome(1) awesomerc(5) awesome(1) awesomerc(5)

View File

@ -26,13 +26,17 @@ regardless of the layout applied. The spiral and dwindle layout are special case
of the tiled layout where the stacking area is arranged in a spiral for the of the tiled layout where the stacking area is arranged in a spiral for the
former or as a rectangular fractal for the later. former or as a rectangular fractal for the later.
Windows are grouped in workspacess. Windows are grouped by tags. Each window can be tagged with one or multiple
tags. Selecting certain tags displays all windows with these tags.
awesome contains a small status bar which displays all available workspaces, awesome contains a small status bar which displays all available tags, the layout,
the layout, the title of the focused window, and a status text. the title of the focused window, and a status text. A
A floating window is indicated with an empty circle and a maximized floating window is indicated with an empty circle and a maximized
floating window is indicated with a circle square before the windows floating window is indicated with a circle square before the windows
title. The selected workspace is indicated with a different color. title. The selected tags are indicated with a different color. The tags of
the focused window are indicated with a filled square in the top left
corner. The tags which are applied to one or more windows are indicated
with an empty square in the top left corner.
awesome can draw a small border around windows to indicate the focus state. awesome can draw a small border around windows to indicate the focus state.
OPTIONS OPTIONS
@ -46,12 +50,20 @@ OPTIONS
DEFAULTS MOUSE BINDINGS DEFAULTS MOUSE BINDINGS
----------------------- -----------------------
*Button1* on workspace name:: *Button1* on tag name::
View workspace. View tag.
*Mod4 + Button1* on tag name::
Tag current client with this tag.
*Button3* on tag name::
Add this tag to current view.
*Mod4 + Button3* on tag name::
Toggle this tag for client.
*Button4*, *Button5* on tag name::
Switch to previous or next tag.
*Button1*, *Button3*, *Button4*, *Button5* on layout symbol:: *Button1*, *Button3*, *Button4*, *Button5* on layout symbol::
Switch to previous or next layout. Switch to previous or next layout.
*Button4*, *Button5* on root window:: *Button4*, *Button5* on root window::
Switch to previous or next workspace. Switch to previous or next tag.
*Mod4 + Button1* on client window:: *Mod4 + Button1* on client window::
Move window. Move window.
*Mod4 + Button3* on client window:: *Mod4 + Button3* on client window::
@ -89,10 +101,12 @@ DEFAULTS KEY BINDINGS
Increase number of columns for non-master windows by 1. Increase number of columns for non-master windows by 1.
*Mod4 \+ Control \+ l*:: *Mod4 \+ Control \+ l*::
Decrease number of columns for non-master windows by 1. Decrease number of columns for non-master windows by 1.
*Mod4 + Escape*::
View previously selected tag.
*Mod4 + Left*:: *Mod4 + Left*::
View previous workspace. View previous tag.
*Mod4 + Right*:: *Mod4 + Right*::
View next workspace. View next tag.
*Mod4 \+ Control \+ space*:: *Mod4 \+ Control \+ space*::
Set client floating. Set client floating.
*Mod4 \+ Shift \+ c*:: *Mod4 \+ Shift \+ c*::
@ -102,9 +116,13 @@ DEFAULTS KEY BINDINGS
*Mod4 \+ Control \+ r*:: *Mod4 \+ Control \+ r*::
Restart awesome. Restart awesome.
*Mod4 + 1-9*:: *Mod4 + 1-9*::
Switch to workspace 1-9. Switch to tag 1-9.
*Mod4 \+ Control \+ 1-9*::
Toggle tag view.
*Mod4 \+ Shift \+ 1-9*:: *Mod4 \+ Shift \+ 1-9*::
Move client to workspace 1-9. Tag client with tag.
*Mod4 \+ Shift \+ Control \+ 1-9*::
Toggle tag on client.
CUSTOMIZATION CUSTOMIZATION
------------- -------------

View File

@ -52,6 +52,7 @@
#include "client.h" #include "client.h"
#include "focus.h" #include "focus.h"
#include "ewmh.h" #include "ewmh.h"
#include "tag.h"
#include "dbus.h" #include "dbus.h"
#include "statusbar.h" #include "statusbar.h"
#include "common/socket.h" #include "common/socket.h"

View File

@ -21,25 +21,33 @@ modkey = "Mod4"
layouts = { "tile", "tileleft", "tilebottom", "tiletop", "magnifier", "max", "spiral", "dwindle", "floating" } layouts = { "tile", "tileleft", "tilebottom", "tiletop", "magnifier", "max", "spiral", "dwindle", "floating" }
-- }}} -- }}}
-- {{{ Workspaces -- {{{ Tags
-- Define workspaces table -- Define tags table
workspaces = {} tags = {}
-- Create 9 workspaces for s = 1, screen.count() do
for i = 1, 9 do -- Each screen has its own tag table
workspaces[i] = workspace.new({ name = i }) tags[s] = {}
workspaces[i]:add(s) -- Create 9 tags per screen
for tagnumber = 1, 9 do
tags[s][tagnumber] = tag.new({ name = tagnumber })
-- Add tags to screen one by one
tags[s][tagnumber]:add(s)
end
-- I'm sure you want to see at least one tag.
tags[s][1]:view(true)
end end
-- I'm sure you want to see at least one workspace
workspaces[1]:screen_set(1)
-- }}} -- }}}
-- {{{ Statusbar -- {{{ Statusbar
-- Create a workspacelist widget -- Create a taglist widget
myworkspacelist = widget.new({ type = "workspacelist", name = "myworkspacelist" }) mytaglist = widget.new({ type = "taglist", name = "mytaglist" })
myworkspacelist:mouse({ }, 1, function (object, workspace) workspace:screen_set(mouse.screen_get()) end) mytaglist:mouse({}, 1, function (object, tag) awful.tag.viewonly(tag) end)
myworkspacelist:mouse({ }, 4, awful.workspace.viewnext) mytaglist:mouse({ modkey }, 1, function (object, tag) awful.client.toggletag(tag) end)
myworkspacelist:mouse({ }, 5, awful.workspace.viewprev) mytaglist:mouse({}, 3, function (object, tag) tag:view(not tag:isselected()) end)
myworkspacelist:set("text_focus", "<bg color=\"#555555\"/> <title/> ") mytaglist:mouse({ modkey }, 3, function (object, tag) awful.client.toggletag(tag) end)
mytaglist:mouse({ }, 4, awful.tag.viewnext)
mytaglist:mouse({ }, 5, awful.tag.viewprev)
mytaglist:set("text_focus", "<bg color=\"#555555\"/> <title/> ")
-- Create a tasklist widget -- Create a tasklist widget
mytasklist = widget.new({ type = "tasklist", name = "mytasklist" }) mytasklist = widget.new({ type = "tasklist", name = "mytasklist" })
@ -74,7 +82,7 @@ for s = 1, screen.count() do
mystatusbar = statusbar.new({ position = "top", name = "mystatusbar" .. s, mystatusbar = statusbar.new({ position = "top", name = "mystatusbar" .. s,
fg = "lightblue", bg = "black" }) fg = "lightblue", bg = "black" })
-- Add widgets to the statusbar - order matters -- Add widgets to the statusbar - order matters
mystatusbar:widget_add(myworkspacelist) mystatusbar:widget_add(mytaglist)
mystatusbar:widget_add(myiconbox) mystatusbar:widget_add(myiconbox)
mystatusbar:widget_add(mytasklist) mystatusbar:widget_add(mytasklist)
mystatusbar:widget_add(mytextbox) mystatusbar:widget_add(mytextbox)
@ -85,8 +93,8 @@ end
-- {{{ Mouse bindings -- {{{ Mouse bindings
awesome.mouse({ }, 3, function () awful.spawn(terminal) end) awesome.mouse({ }, 3, function () awful.spawn(terminal) end)
awesome.mouse({ }, 4, awful.workspace.viewnext) awesome.mouse({ }, 4, awful.tag.viewnext)
awesome.mouse({ }, 5, awful.workspace.viewprev) awesome.mouse({ }, 5, awful.tag.viewprev)
client.mouse({ }, 1, function (c) c:focus_set(); c:raise() end) client.mouse({ }, 1, function (c) c:focus_set(); c:raise() end)
client.mouse({ modkey }, 1, function (c) c:mouse_move() end) client.mouse({ modkey }, 1, function (c) c:mouse_move() end)
client.mouse({ modkey }, 3, function (c) c:mouse_resize() end) client.mouse({ modkey }, 3, function (c) c:mouse_resize() end)
@ -96,20 +104,44 @@ client.mouse({ modkey }, 3, function (c) c:mouse_resize() end)
-- Bind keyboard digits -- Bind keyboard digits
-- Compute the maximum number of digit we need, limited to 9 -- Compute the maximum number of digit we need, limited to 9
keynumber = math.min(9, #workspaces); keynumber = 0
for s = 1, screen.count() do
keynumber = math.min(9, math.max(#tags[s], keynumber));
end
for i = 1, keynumber do for i = 1, keynumber do
keybinding.new({ modkey }, i, keybinding.new({ modkey }, i,
function () function ()
workspaces[i]:screen_set(mouse.screen_get()) local screen = mouse.screen_get()
if tags[screen][i] then
awful.tag.viewonly(tags[screen][i])
end
end):add()
keybinding.new({ modkey, "Control" }, i,
function ()
local screen = mouse.screen_get()
if tags[screen][i] then
tags[i]:view(not tags[screen][i]:isselected())
end
end):add() end):add()
keybinding.new({ modkey, "Shift" }, i, keybinding.new({ modkey, "Shift" }, i,
function () function ()
client.focus_get():workspace_set(workspaces[i]) local screen = mouse.screen_get()
if tags[screen][i] then
awful.client.movetotag(tags[screen][i])
end
end):add()
keybinding.new({ modkey, "Control", "Shift" }, i,
function ()
local screen = mouse.screen_get()
if tags[screen][i] then
awful.client.toggletag(tags[screen][i])
end
end):add() end):add()
end end
keybinding.new({ modkey }, "Left", awful.workspace.viewprev):add() keybinding.new({ modkey }, "Left", awful.tag.viewprev):add()
keybinding.new({ modkey }, "Right", awful.workspace.viewnext):add() keybinding.new({ modkey }, "Right", awful.tag.viewnext):add()
-- Standard program -- Standard program
keybinding.new({ modkey }, "Return", function () awful.spawn(terminal) end):add() keybinding.new({ modkey }, "Return", function () awful.spawn(terminal) end):add()
@ -129,12 +161,12 @@ keybinding.new({ modkey, "Control" }, "space", awful.client.togglefloating):add(
keybinding.new({ modkey }, "o", awful.client.movetoscreen):add() keybinding.new({ modkey }, "o", awful.client.movetoscreen):add()
-- Layout manipulation -- Layout manipulation
keybinding.new({ modkey }, "l", function () awful.workspace.incmwfact(0.05) end):add() keybinding.new({ modkey }, "l", function () awful.tag.incmwfact(0.05) end):add()
keybinding.new({ modkey }, "h", function () awful.workspace.incmwfact(-0.05) end):add() keybinding.new({ modkey }, "h", function () awful.tag.incmwfact(-0.05) end):add()
keybinding.new({ modkey, "Shift" }, "h", function () awful.workspace.incnmaster(1) end):add() keybinding.new({ modkey, "Shift" }, "h", function () awful.tag.incnmaster(1) end):add()
keybinding.new({ modkey, "Shift" }, "l", function () awful.workspace.incnmaster(-1) end):add() keybinding.new({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end):add()
keybinding.new({ modkey, "Control" }, "h", function () awful.workspace.incncol(1) end):add() keybinding.new({ modkey, "Control" }, "h", function () awful.tag.incncol(1) end):add()
keybinding.new({ modkey, "Control" }, "l", function () awful.workspace.incncol(1) end):add() keybinding.new({ modkey, "Control" }, "l", function () awful.tag.incncol(1) end):add()
keybinding.new({ modkey }, "space", function () awful.layout.inc(layouts, 1) end):add() keybinding.new({ modkey }, "space", function () awful.layout.inc(layouts, 1) end):add()
keybinding.new({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end):add() keybinding.new({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end):add()
-- }}} -- }}}
@ -153,7 +185,7 @@ end
-- Hook function to exeucte when the mouse is over a client. -- Hook function to exeucte when the mouse is over a client.
function hook_mouseover(c) function hook_mouseover(c)
-- Sloppy focus, but disabled for magnifier layout -- Sloppy focus, but disabled for magnifier layout
if c:workspace_get():layout_get() ~= "magnifier" then if awful.layout.get(c:screen_get()) ~= "magnifier" then
c:focus_set() c:focus_set()
end end
end end
@ -170,10 +202,10 @@ function hook_newclient(c)
end end
-- Hook function to execute when arranging the screen -- Hook function to execute when arranging the screen
-- (workspace switch, new client, etc) -- (tag switch, new client, etc)
function hook_arrange(ws) function hook_arrange(screen)
local screen = ws:screen_get() local layout = awful.layout.get(screen)
mylayoutbox[screen]:set("image", "@iconsdir@/layouts/" .. ws:layout_get() .. "w.png") mylayoutbox[screen]:set("image", "@iconsdir@/layouts/" .. layout .. "w.png")
end end
-- Hook called every second -- Hook called every second

165
awful.lua
View File

@ -20,7 +20,7 @@ local pairs = pairs
local awesome = awesome local awesome = awesome
local screen = screen local screen = screen
local client = client local client = client
local workspace = workspace local tag = tag
local mouse = mouse local mouse = mouse
local os = os local os = os
local table = table local table = table
@ -84,7 +84,13 @@ function client_moveresize(x, y, w, h)
end end
function screen_focus(i) function screen_focus(i)
local s = mouse.screen_get() local sel = client.focus_get()
local s
if sel then
s = sel:screen_get()
else
s = mouse.screen_get()
end
local count = screen.count() local count = screen.count()
s = s + i s = s + i
if s < 1 then if s < 1 then
@ -92,81 +98,136 @@ function screen_focus(i)
elseif s > count then elseif s > count then
s = 1 s = 1
end end
local ws = screen.workspace_get(s) screen.focus(s)
if ws then
ws:focus_set()
end
-- Move the mouse on the screen -- Move the mouse on the screen
local screen_coords = screen.coords_get(s) local screen_coords = screen.coords_get(s)
mouse.coords_set(screen_coords['x'], screen_coords['y']) mouse.coords_set(screen_coords['x'], screen_coords['y'])
end end
-- Return a table with all visible tags
function tag_selectedlist(s)
local idx = 1
local screen = s or mouse.screen_get()
local tags = tag.get(screen)
local vtags = {}
for i, t in ipairs(tags) do
if t:isselected() then
vtags[idx] = t
idx = idx + 1
end
end
return vtags
end
-- Return only the first element of all visible tags,
-- so that's the first visible tags.
function tag_selected(s)
return tag_selectedlist(s)[1]
end
-- Set master width factor -- Set master width factor
function workspace_setmwfact(i) function tag_setmwfact(i)
local t = workspace_selected() local t = tag_selected()
if t then if t then
t:mwfact_set(i) t:mwfact_set(i)
end end
end end
-- Increase master width factor -- Increase master width factor
function workspace_incmwfact(i) function tag_incmwfact(i)
local t = workspace_selected() local t = tag_selected()
if t then if t then
t:mwfact_set(t:mwfact_get() + i) t:mwfact_set(t:mwfact_get() + i)
end end
end end
-- Set number of master windows -- Set number of master windows
function workspace_setnmaster(i) function tag_setnmaster(i)
local t = workspace_selected() local t = tag_selected()
if t then if t then
t:nmaster_set(i) t:nmaster_set(i)
end end
end end
-- Increase number of master windows -- Increase number of master windows
function workspace_incnmaster(i) function tag_incnmaster(i)
local t = workspace_selected() local t = tag_selected()
if t then if t then
t:nmaster_set(t:nmaster_get() + i) t:nmaster_set(t:nmaster_get() + i)
end end
end end
-- Set number of column windows -- Set number of column windows
function workspace_setncol(i) function tag_setncol(i)
local t = workspace_selected() local t = tag_selected()
if t then if t then
t:ncol_set(i) t:ncol_set(i)
end end
end end
-- Increase number of column windows -- Increase number of column windows
function workspace_incncol(i) function tag_incncol(i)
local t = workspace_selected() local t = tag_selected()
if t then if t then
t:ncol_set(t:ncol_get() + i) t:ncol_set(t:ncol_get() + i)
end end
end end
function workspace_viewidx(r) -- View no tag
local workspaces = workspace.get() function tag_viewnone()
local sel = workspace.visible_get(mouse.screen_get()) local tags = tag.get(mouse.screen_get())
for i, t in ipairs(workspaces) do for i, t in ipairs(tags) do
t:view(false)
end
end
function tag_viewidx(r)
local tags = tag.get(mouse.screen_get())
local sel = tag_selected()
tag_viewnone()
for i, t in ipairs(tags) do
if t == sel then if t == sel then
workspaces[array_boundandcycle(workspaces, i + r)]:screen_set(mouse.screen_get()) tags[array_boundandcycle(tags, i + r)]:view(true)
end end
end end
end end
-- View next workspace -- View next tag
function workspace_viewnext() function tag_viewnext()
return workspace_viewidx(1) return tag_viewidx(1)
end end
-- View previous workspace -- View previous tag
function workspace_viewprev() function tag_viewprev()
return workspace_viewidx(-1) return tag_viewidx(-1)
end
function tag_viewonly(t)
tag_viewnone()
t:view(true)
end
function tag_viewmore(tags)
tag_viewnone()
for i, t in ipairs(tags) do
t:view(true)
end
end
function client_movetotag(target, c)
local sel = c or client.focus_get();
local tags = tag.get(mouse.screen_get())
for i, t in ipairs(tags) do
sel:tag(t, false)
end
sel:tag(target, true)
end
function client_toggletag(target, c)
local sel = c or client.focus_get();
if sel then
sel:tag(target, not sel:istagged(target))
end
end end
function client_togglefloating(c) function client_togglefloating(c)
@ -189,11 +250,18 @@ function client_movetoscreen(c, s)
end end
end end
-- Function to change the layout of the current workspace. function layout_get(screen)
local t = tag_selected(screen)
if t then
return t:layout_get()
end
end
-- Function to change the layout of the current tag.
-- layouts = table of layouts (define in .awesomerc.lua) -- layouts = table of layouts (define in .awesomerc.lua)
-- i = relative index -- i = relative index
function layout_inc(layouts, i) function layout_inc(layouts, i)
local t = workspace.visible_get(mouse.screen_get()) local t = tag_selected()
local number_of_layouts = 0 local number_of_layouts = 0
local rev_layouts = {} local rev_layouts = {}
for i, v in ipairs(layouts) do for i, v in ipairs(layouts) do
@ -201,7 +269,7 @@ function layout_inc(layouts, i)
number_of_layouts = number_of_layouts + 1 number_of_layouts = number_of_layouts + 1
end end
if t then if t then
local cur_layout = t:layout_get() local cur_layout = layout_get()
local new_layout_index = (rev_layouts[cur_layout] + i) % number_of_layouts local new_layout_index = (rev_layouts[cur_layout] + i) % number_of_layouts
if new_layout_index == 0 then if new_layout_index == 0 then
new_layout_index = number_of_layouts new_layout_index = number_of_layouts
@ -210,9 +278,9 @@ function layout_inc(layouts, i)
end end
end end
-- function to set the layout of the current workspace by name. -- function to set the layout of the current tag by name.
function layout_set(layout) function layout_set(layout)
local t = workspace.visible_get(mouse.screen_get()) local t = tag_selected()
if t then if t then
t:layout_set(layout) t:layout_set(layout)
end end
@ -272,24 +340,30 @@ function spawn(cmd)
return os.execute(cmd .. "&") return os.execute(cmd .. "&")
end end
-- Export workspaces function -- Export tags function
P.workspace = P.tag =
{ {
viewprev = workspace_viewprev; viewnone = tag_viewnone;
viewnext = workspace_viewnext; viewprev = tag_viewprev;
setmwfact = workspace_setmwfact; viewnext = tag_viewnext;
incmwfact = workspace_incmwfact; viewonly = tag_viewonly;
setncol = workspace_setncol; viewmore = tag_viewmore;
incncol = workspace_incncol; setmwfact = tag_setmwfact;
setnmaster = workspace_setnmaster; incmwfact = tag_incmwfact;
incnmaster = workspace_incnmaster; setncol = tag_setncol;
incncol = tag_incncol;
setnmaster = tag_setnmaster;
incnmaster = tag_incnmaster;
selected = tag_selected;
selectedlist = tag_selectedlist;
} }
P.client = P.client =
{ {
next = client_next; next = client_next;
focus = client_focus; focus = client_focus;
swap = client_swap; swap = client_swap;
movetoworkspace = client_movetoworkspace; movetotag = client_movetotag;
toggletag = client_toggletag;
togglefloating = client_togglefloating; togglefloating = client_togglefloating;
moveresize = client_moveresize; moveresize = client_moveresize;
movetoscreen = client_movetoscreen; movetoscreen = client_movetoscreen;
@ -300,6 +374,7 @@ P.screen =
} }
P.layout = P.layout =
{ {
get = layout_get;
set = layout_set; set = layout_set;
inc = layout_inc; inc = layout_inc;
} }

264
client.c
View File

@ -27,7 +27,7 @@
#include <xcb/shape.h> #include <xcb/shape.h>
#include "client.h" #include "client.h"
#include "workspace.h" #include "tag.h"
#include "window.h" #include "window.h"
#include "focus.h" #include "focus.h"
#include "ewmh.h" #include "ewmh.h"
@ -44,40 +44,40 @@
extern awesome_t globalconf; extern awesome_t globalconf;
/** Load windows properties, restoring client's workspace /** Load windows properties, restoring client's tag
* and floating state before awesome was restarted if any. * and floating state before awesome was restarted if any.
* \todo This may bug if number of workspacess is != than before. * \todo This may bug if number of tags is != than before.
* \param c A client pointer. * \param c A client pointer.
* \param screen A virtual screen number.
* \return True if client had property, false otherwise. * \return True if client had property, false otherwise.
*/ */
static bool static bool
client_loadprops(client_t * c) client_loadprops(client_t * c, int screen)
{ {
int i, nworkspaces = 0; int i, ntags = 0;
workspace_t *workspace; tag_t *tag;
char *prop = NULL; char *prop = NULL;
bool result = false; bool result = false;
xutil_intern_atom_request_t atom_q;
atom_q = xutil_intern_atom(globalconf.connection, &globalconf.atoms, "_AWESOME_PROPERTIES"); for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
ntags++;
for(workspace = globalconf.workspaces; workspace; workspace = workspace->next)
nworkspaces++;
if(xutil_gettextprop(globalconf.connection, c->win, &globalconf.atoms, if(xutil_gettextprop(globalconf.connection, c->win, &globalconf.atoms,
xutil_intern_atom_reply(globalconf.connection, &globalconf.atoms, atom_q), xutil_intern_atom_reply(globalconf.connection, &globalconf.atoms,
xutil_intern_atom(globalconf.connection,
&globalconf.atoms,
"_AWESOME_PROPERTIES")),
&prop)) &prop))
{ {
for(i = 0, workspace = globalconf.workspaces; workspace && i < nworkspaces && prop[i]; i++, workspace = workspace->next) for(i = 0, tag = globalconf.screens[screen].tags; tag && i < ntags && prop[i]; i++, tag = tag->next)
if(prop[i] == '1') if(prop[i] == '1')
{ {
workspace_client_set(c, workspace); tag_client(c, tag);
result = true; result = true;
break;
} }
else
untag_client(c, tag);
/* jump to the end */
i = nworkspaces;
if(prop[i]) if(prop[i])
client_setfloating(c, prop[i] == '1', client_setfloating(c, prop[i] == '1',
(prop[i + 1] >= 0 && prop[i + 1] <= LAYER_FULLSCREEN) ? atoi(&prop[i + 1]) : prop[i] == '1' ? LAYER_FLOAT : LAYER_TILE); (prop[i + 1] >= 0 && prop[i + 1] <= LAYER_FULLSCREEN) ? atoi(&prop[i + 1]) : prop[i] == '1' ? LAYER_FLOAT : LAYER_TILE);
@ -115,42 +115,43 @@ window_isprotodel(xcb_window_t win)
return ret; return ret;
} }
/** Returns true if a client is on a workspace visible /** Returns true if a client is tagged with one of the tags visibl
* on any screen. * on any screen.
* \param c The client. * \param c The client.
* \return True if client is visible, false otherwise. * \return True if client is tagged, false otherwise.
*/ */
static bool static bool
client_isvisible_anyscreen(client_t *c) client_isvisible_anyscreen(client_t *c)
{ {
workspace_t *ws; tag_t *tag;
int screen; int screen;
if(c && !c->ishidden) if(c && !c->ishidden)
{
ws = workspace_client_get(c);
for(screen = 0; screen < globalconf.screens_info->nscreen; screen++) for(screen = 0; screen < globalconf.screens_info->nscreen; screen++)
if(globalconf.screens[screen].workspace == ws) for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
if(tag->selected && is_client_tagged(c, tag))
return true; return true;
}
return false; return false;
} }
/** Returns true if a client is on the workspace visible on the specified /** Returns true if a client is tagged
* screen. * with one of the tags of the specified screen.
* \param c The client to check. * \param c The client to check.
* \param screen Virtual screen number. * \param screen Virtual screen number.
* \return True if the client is visible, false otherwise. * \return true if the client is visible, false otherwise.
*/ */
bool bool
client_isvisible(client_t *c, int screen) client_isvisible(client_t *c, int screen)
{ {
if(c && !c->ishidden) tag_t *tag;
return (workspace_client_get(c) == globalconf.screens[screen].workspace);
if(c && !c->ishidden && c->screen == screen)
for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
if(tag->selected && is_client_tagged(c, tag))
return true;
return false; return false;
} }
/** Get a client by its window. /** Get a client by its window.
* \param w The client window to find. * \param w The client window to find.
* \return A client pointer if found, NULL otherwise. * \return A client pointer if found, NULL otherwise.
@ -193,18 +194,18 @@ client_updatetitle(client_t *c)
luaA_client_userdata_new(c); luaA_client_userdata_new(c);
luaA_dofunction(globalconf.L, globalconf.hooks.titleupdate, 1); luaA_dofunction(globalconf.L, globalconf.hooks.titleupdate, 1);
widget_invalidate_cache(WIDGET_CACHE_CLIENTS); widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
} }
static void static void
client_unfocus(client_t *c) client_unfocus(client_t *c)
{ {
/* Call hook */ /* Call hook */
luaA_client_userdata_new(c); luaA_client_userdata_new(globalconf.focus->client);
luaA_dofunction(globalconf.L, globalconf.hooks.unfocus, 1); luaA_dofunction(globalconf.L, globalconf.hooks.unfocus, 1);
focus_client_push(NULL); focus_client_push(NULL);
widget_invalidate_cache(WIDGET_CACHE_CLIENTS); widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
} }
/** Ban client and unmap it /** Ban client and unmap it
@ -223,20 +224,26 @@ client_ban(client_t *c)
/** Give focus to client, or to first client if client is NULL, /** Give focus to client, or to first client if client is NULL,
* \param c The client or NULL. * \param c The client or NULL.
* \return True if a window (even root). * \param screen Virtual screen number.
* \return True if a window (even root) has received focus, false otherwise.
*/ */
bool bool
client_focus(client_t *c) client_focus(client_t *c, int screen)
{ {
int phys_screen; int phys_screen;
if(!c) /* if c is NULL or invisible, take next client in the focus history */
return false; if((!c || (c && (!client_isvisible(c, screen))))
&& !(c = focus_get_current_client(screen)))
/* if c is still NULL take next client in the stack */
for(c = globalconf.clients; c && (c->skip || !client_isvisible(c, screen)); c = c->next);
/* unfocus current selected client */ /* unfocus current selected client */
if(globalconf.focus->client) if(globalconf.focus->client)
client_unfocus(globalconf.focus->client); client_unfocus(globalconf.focus->client);
if(c)
{
/* unban the client before focusing or it will fail */ /* unban the client before focusing or it will fail */
client_unban(c); client_unban(c);
/* save sel in focus history */ /* save sel in focus history */
@ -249,14 +256,23 @@ client_focus(client_t *c)
phys_screen = c->phys_screen; phys_screen = c->phys_screen;
/* Some layouts use focused client differently, so call them back. */ /* Some layouts use focused client differently, so call them back. */
workspace_client_get(c)->need_arrange = true; globalconf.screens[c->screen].need_arrange = true;
/* execute hook */ /* execute hook */
luaA_client_userdata_new(globalconf.focus->client); luaA_client_userdata_new(globalconf.focus->client);
luaA_dofunction(globalconf.L, globalconf.hooks.focus, 1); luaA_dofunction(globalconf.L, globalconf.hooks.focus, 1);
}
else
{
phys_screen = screen_virttophys(screen);
xcb_set_input_focus(globalconf.connection,
XCB_INPUT_FOCUS_POINTER_ROOT,
xcb_aux_get_screen(globalconf.connection, phys_screen)->root,
XCB_CURRENT_TIME);
}
ewmh_update_net_active_window(phys_screen); ewmh_update_net_active_window(phys_screen);
widget_invalidate_cache(WIDGET_CACHE_CLIENTS); widget_invalidate_cache(screen, WIDGET_CACHE_CLIENTS);
return true; return true;
} }
@ -312,20 +328,20 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int screen)
client_t *c, *t = NULL; client_t *c, *t = NULL;
xcb_window_t trans; xcb_window_t trans;
bool rettrans, retloadprops; bool rettrans, retloadprops;
tag_t *tag;
xcb_size_hints_t *u_size_hints; xcb_size_hints_t *u_size_hints;
int rscreen;
const uint32_t select_input_val[] = { const uint32_t select_input_val[] = {
XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE |
XCB_EVENT_MASK_ENTER_WINDOW }; XCB_EVENT_MASK_ENTER_WINDOW };
c = p_new(client_t, 1); c = p_new(client_t, 1);
rscreen = screen_get_bycoord(globalconf.screens_info, screen, wgeom->x, wgeom->y); c->screen = screen_get_bycoord(globalconf.screens_info, screen, wgeom->x, wgeom->y);
if(globalconf.screens_info->xinerama_is_active) if(globalconf.screens_info->xinerama_is_active)
c->phys_screen = globalconf.default_screen; c->phys_screen = globalconf.default_screen;
else else
c->phys_screen = rscreen; c->phys_screen = c->screen;
/* Initial values */ /* Initial values */
c->win = w; c->win = w;
@ -341,16 +357,18 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int screen)
client_updatewmhints(c); client_updatewmhints(c);
/* Try to load props if any */ /* Try to load props if any */
if(!(retloadprops = client_loadprops(c))) if(!(retloadprops = client_loadprops(c, screen)))
workspace_client_set(c, globalconf.screens[screen].workspace); screen_client_moveto(c, screen, true);
/* Then check clients hints */ /* Then check clients hints */
ewmh_check_client_hints(c); ewmh_check_client_hints(c);
/* check for transient and set on same workspace like its parent */ /* check for transient and set tags like its parent */
if((rettrans = xutil_get_transient_for_hint(globalconf.connection, w, &trans)) if((rettrans = xutil_get_transient_for_hint(globalconf.connection, w, &trans))
&& (t = client_getbywin(trans))) && (t = client_getbywin(trans)))
workspace_client_set(c, workspace_client_get(t)); for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
if(is_client_tagged(t, tag))
tag_client(c, tag);
/* should be floating if transsient or fixed */ /* should be floating if transsient or fixed */
if(rettrans || c->isfixed) if(rettrans || c->isfixed)
@ -388,7 +406,7 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int screen)
/* Push client in stack */ /* Push client in stack */
stack_client_push(c); stack_client_push(c);
widget_invalidate_cache(WIDGET_CACHE_CLIENTS); widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
ewmh_update_net_client_list(c->phys_screen); ewmh_update_net_client_list(c->phys_screen);
/* update window title */ /* update window title */
@ -455,16 +473,15 @@ client_geometry_hints(client_t *c, area_t geometry)
bool bool
client_resize(client_t *c, area_t geometry, bool hints) client_resize(client_t *c, area_t geometry, bool hints)
{ {
int screen, new_screen; int new_screen;
workspace_t *ws; area_t area;
layout_t *layout = layout_get_current(c->screen);
bool resized = false; bool resized = false;
/* Values to configure a window is an array where values are /* Values to configure a window is an array where values are
* stored according to 'value_mask' */ * stored according to 'value_mask' */
uint32_t values[5]; uint32_t values[5];
ws = workspace_client_get(c); if(c->titlebar && !c->ismoving && !c->isfloating && layout != layout_floating)
if(c->titlebar && !c->ismoving && !c->isfloating && ws->layout != layout_floating)
{ {
titlebar_update_geometry(c, geometry); titlebar_update_geometry(c, geometry);
geometry = titlebar_geometry_remove(c->titlebar, geometry); geometry = titlebar_geometry_remove(c->titlebar, geometry);
@ -476,12 +493,24 @@ client_resize(client_t *c, area_t geometry, bool hints)
if(geometry.width <= 0 || geometry.height <= 0) if(geometry.width <= 0 || geometry.height <= 0)
return false; return false;
/* offscreen appearance fixes */
area = display_area_get(c->phys_screen, NULL,
&globalconf.screens[c->screen].padding);
if(geometry.x > area.width)
geometry.x = area.width - geometry.width - 2 * c->border;
if(geometry.y > area.height)
geometry.y = area.height - geometry.height - 2 * c->border;
if(geometry.x + geometry.width + 2 * c->border < 0)
geometry.x = 0;
if(geometry.y + geometry.height + 2 * c->border < 0)
geometry.y = 0;
if(c->geometry.x != geometry.x || c->geometry.y != geometry.y if(c->geometry.x != geometry.x || c->geometry.y != geometry.y
|| c->geometry.width != geometry.width || c->geometry.height != geometry.height) || c->geometry.width != geometry.width || c->geometry.height != geometry.height)
{ {
screen = workspace_screen_get(ws);
new_screen = new_screen =
screen_get_bycoord(globalconf.screens_info, screen, geometry.x, geometry.y); screen_get_bycoord(globalconf.screens_info, c->screen, geometry.x, geometry.y);
c->geometry.x = values[0] = geometry.x; c->geometry.x = values[0] = geometry.x;
c->geometry.width = values[2] = geometry.width; c->geometry.width = values[2] = geometry.width;
@ -492,7 +521,7 @@ client_resize(client_t *c, area_t geometry, bool hints)
/* save the floating geometry if the window is floating but not /* save the floating geometry if the window is floating but not
* maximized */ * maximized */
if(c->ismoving || c->isfloating if(c->ismoving || c->isfloating
|| ws->layout == layout_floating) || layout_get_current(new_screen) == layout_floating)
{ {
titlebar_update_geometry_floating(c); titlebar_update_geometry_floating(c);
if(!c->ismax) if(!c->ismax)
@ -506,12 +535,15 @@ client_resize(client_t *c, area_t geometry, bool hints)
values); values);
window_configure(c->win, geometry, c->border); window_configure(c->win, geometry, c->border);
if(c->screen != new_screen)
screen_client_moveto(c, new_screen, false);
resized = true; resized = true;
} }
/* call it again like it was floating, /* call it again like it was floating,
* we want it to be sticked to the window */ * we want it to be sticked to the window */
if(!c->ismoving && !c->isfloating && ws->layout != layout_floating) if(!c->ismoving && !c->isfloating && layout != layout_floating)
titlebar_update_geometry_floating(c); titlebar_update_geometry_floating(c);
return resized; return resized;
@ -534,8 +566,9 @@ client_setfloating(client_t *c, bool floating, layer_t layer)
c->ismax = false; c->ismax = false;
client_resize(c, c->m_geometry, false); client_resize(c, c->m_geometry, false);
} }
workspace_client_get(c)->need_arrange = true; if(client_isvisible(c, c->screen))
widget_invalidate_cache(WIDGET_CACHE_CLIENTS); globalconf.screens[c->screen].need_arrange = true;
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
if(floating) if(floating)
{ {
c->oldlayer = c->layer; c->oldlayer = c->layer;
@ -554,23 +587,20 @@ client_setfloating(client_t *c, bool floating, layer_t layer)
void void
client_saveprops(client_t *c) client_saveprops(client_t *c)
{ {
int i = 0, nws = 0; int i = 0, ntags = 0;
char *prop; char *prop;
workspace_t *workspace, *cws = workspace_client_get(c); tag_t *tag;
xutil_intern_atom_request_t atom_q; xutil_intern_atom_request_t atom_q;
atom_q = xutil_intern_atom(globalconf.connection, &globalconf.atoms, "_AWESOME_PROPERTIES"); atom_q = xutil_intern_atom(globalconf.connection, &globalconf.atoms, "_AWESOME_PROPERTIES");
for(workspace = globalconf.workspaces; workspace; workspace = workspace->next) for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
nws++; ntags++;
prop = p_new(char, nws + 3); prop = p_new(char, ntags + 3);
for(workspace = globalconf.workspaces; workspace; workspace = workspace->next, i++) for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next, i++)
if(cws == workspace) prop[i] = is_client_tagged(c, tag) ? '1' : '0';
prop[i] = '1';
else
prop[i] = '0';
prop[i] = c->isfloating ? '1' : '0'; prop[i] = c->isfloating ? '1' : '0';
@ -597,6 +627,8 @@ client_unban(client_t *c)
void void
client_unmanage(client_t *c) client_unmanage(client_t *c)
{ {
tag_t *tag;
/* The server grab construct avoids race conditions. */ /* The server grab construct avoids race conditions. */
xcb_grab_server(globalconf.connection); xcb_grab_server(globalconf.connection);
@ -608,11 +640,11 @@ client_unmanage(client_t *c)
client_list_detach(&globalconf.clients, c); client_list_detach(&globalconf.clients, c);
focus_client_delete(c); focus_client_delete(c);
stack_client_delete(c); stack_client_delete(c);
for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
untag_client(c, tag);
if(globalconf.focus->client == c) if(globalconf.focus->client == c)
client_focus(focus_client_getcurrent(workspace_client_get(c))); client_focus(NULL, c->screen);
workspace_client_remove(c);
xcb_ungrab_button(globalconf.connection, XCB_BUTTON_INDEX_ANY, c->win, ANY_MODIFIER); xcb_ungrab_button(globalconf.connection, XCB_BUTTON_INDEX_ANY, c->win, ANY_MODIFIER);
window_setstate(c->win, XCB_WM_WITHDRAWN_STATE); window_setstate(c->win, XCB_WM_WITHDRAWN_STATE);
@ -647,7 +679,7 @@ client_updatewmhints(client_t *c)
luaA_client_userdata_new(c); luaA_client_userdata_new(c);
luaA_dofunction(globalconf.L, globalconf.hooks.urgent, 1); luaA_dofunction(globalconf.L, globalconf.hooks.urgent, 1);
widget_invalidate_cache(WIDGET_CACHE_CLIENTS); widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
} }
if((wm_hints_flags & XCB_WM_STATE_HINT) && if((wm_hints_flags & XCB_WM_STATE_HINT) &&
(xcb_wm_hints_get_initial_state(wmh) == XCB_WM_WITHDRAWN_STATE)) (xcb_wm_hints_get_initial_state(wmh) == XCB_WM_WITHDRAWN_STATE))
@ -883,7 +915,7 @@ client_setborder(client_t *c, uint32_t width)
c->border = width; c->border = width;
xcb_configure_window(globalconf.connection, c->win, xcb_configure_window(globalconf.connection, c->win,
XCB_CONFIG_WINDOW_BORDER_WIDTH, &width); XCB_CONFIG_WINDOW_BORDER_WIDTH, &width);
workspace_client_get(c)->need_arrange = true; globalconf.screens[c->screen].need_arrange = true;
} }
/** Set the client border width and color. /** Set the client border width and color.
@ -908,28 +940,64 @@ luaA_client_border_set(lua_State *L)
return 0; return 0;
} }
/** Set the client on the specified workspace. /** Move the client to another screen.
* \param A workspace object. * \param A screen number.
*/ */
static int static int
luaA_client_workspace_set(lua_State *L) luaA_client_screen_set(lua_State *L)
{ {
client_t **c = luaA_checkudata(L, 1, "client"); client_t **c = luaA_checkudata(L, 1, "client");
workspace_t **workspace = luaA_checkudata(L, 2, "workspace"); int screen = luaL_checknumber(L, 2) - 1;
/* arrange old ws */ luaA_checkscreen(screen);
workspace_client_get(*c)->need_arrange = true; screen_client_moveto(*c, screen, true);
workspace_client_set(*c, *workspace);
return 0; return 0;
} }
/** Get the workspace the client is on. /** Get the screen number the client is onto.
* \return A workspace. * \return A screen number.
*/ */
static int static int
luaA_client_workspace_get(lua_State *L) luaA_client_screen_get(lua_State *L)
{ {
client_t **c = luaA_checkudata(L, 1, "client"); client_t **c = luaA_checkudata(L, 1, "client");
return luaA_workspace_userdata_new(workspace_client_get(*c)); lua_pushnumber(L, 1 + (*c)->screen);
return 1;
}
/** Tag a client with a specified tag.
* \param A tag object.
* \param A boolean value: true to add this tag to clients, false to remove.
*/
static int
luaA_client_tag(lua_State *L)
{
client_t **c = luaA_checkudata(L, 1, "client");
tag_t **tag = luaA_checkudata(L, 2, "tag");
bool tag_the_client = luaA_checkboolean(L, 3);
if((*tag)->screen != (*c)->screen)
luaL_error(L, "tag and client are on different screens");
if(tag_the_client)
tag_client(*c, *tag);
else
untag_client(*c, *tag);
return 0;
}
/** Check if a client is tagged with the specified tag.
* \param A tag object.
* \return A boolean value, true if the client is tagged with this tag, false
* otherwise.
*/
static int
luaA_client_istagged(lua_State *L)
{
client_t **c = luaA_checkudata(L, 1, "client");
tag_t **tag = luaA_checkudata(L, 2, "tag");
lua_pushboolean(L, is_client_tagged(*c, *tag));
return 1;
} }
/** Get the client coordinates on the display. /** Get the client coordinates on the display.
@ -957,7 +1025,7 @@ luaA_client_coords_set(lua_State *L)
client_t **c = luaA_checkudata(L, 1, "client"); client_t **c = luaA_checkudata(L, 1, "client");
area_t geometry; area_t geometry;
if((*c)->isfloating || workspace_client_get(*c)->layout == layout_floating) if((*c)->isfloating || layout_get_current((*c)->screen) == layout_floating)
{ {
luaA_checktable(L, 2); luaA_checktable(L, 2);
geometry.x = luaA_getopt_number(L, 2, "x", (*c)->geometry.x); geometry.x = luaA_getopt_number(L, 2, "x", (*c)->geometry.x);
@ -995,9 +1063,10 @@ luaA_client_swap(lua_State *L)
client_t **c = luaA_checkudata(L, 1, "client"); client_t **c = luaA_checkudata(L, 1, "client");
client_t **swap = luaA_checkudata(L, 2, "client"); client_t **swap = luaA_checkudata(L, 2, "client");
client_list_swap(&globalconf.clients, *swap, *c); client_list_swap(&globalconf.clients, *swap, *c);
workspace_client_get(*c)->need_arrange = true; globalconf.screens[(*c)->screen].need_arrange = true;
workspace_client_get(*swap)->need_arrange = true; globalconf.screens[(*swap)->screen].need_arrange = true;
widget_invalidate_cache(WIDGET_CACHE_CLIENTS); widget_invalidate_cache((*c)->screen, WIDGET_CACHE_CLIENTS);
widget_invalidate_cache((*swap)->screen, WIDGET_CACHE_CLIENTS);
return 0; return 0;
} }
@ -1005,7 +1074,7 @@ static int
luaA_client_focus_set(lua_State *L) luaA_client_focus_set(lua_State *L)
{ {
client_t **c = luaA_checkudata(L, 1, "client"); client_t **c = luaA_checkudata(L, 1, "client");
client_focus(*c); client_focus(*c, (*c)->screen);
return 0; return 0;
} }
@ -1121,7 +1190,6 @@ luaA_client_titlebar_set(lua_State *L)
{ {
client_t **c = luaA_checkudata(L, 1, "client"); client_t **c = luaA_checkudata(L, 1, "client");
titlebar_t **t = luaA_checkudata(L, 2, "titlebar"); titlebar_t **t = luaA_checkudata(L, 2, "titlebar");
workspace_t *ws;
if(client_getbytitlebar(*t)) if(client_getbytitlebar(*t))
luaL_error(L, "titlebar is already used by another client"); luaL_error(L, "titlebar is already used by another client");
@ -1135,12 +1203,10 @@ luaA_client_titlebar_set(lua_State *L)
titlebar_ref(t); titlebar_ref(t);
titlebar_init(*c); titlebar_init(*c);
ws = workspace_client_get(*c); if((*c)->isfloating || layout_get_current((*c)->screen) == layout_floating)
if((*c)->isfloating || ws->layout == layout_floating)
titlebar_update_geometry_floating(*c); titlebar_update_geometry_floating(*c);
else else
ws->need_arrange = true; globalconf.screens[(*c)->screen].need_arrange = true;
return 0; return 0;
} }
@ -1176,7 +1242,7 @@ luaA_client_hide(lua_State *L)
{ {
client_t **c = luaA_checkudata(L, 1, "client"); client_t **c = luaA_checkudata(L, 1, "client");
(*c)->ishidden = true; (*c)->ishidden = true;
workspace_client_get(*c)->need_arrange = true; globalconf.screens[(*c)->screen].need_arrange = true;
return 0; return 0;
} }
@ -1187,7 +1253,7 @@ luaA_client_unhide(lua_State *L)
{ {
client_t **c = luaA_checkudata(L, 1, "client"); client_t **c = luaA_checkudata(L, 1, "client");
(*c)->ishidden = false; (*c)->ishidden = false;
workspace_client_get(*c)->need_arrange = true; globalconf.screens[(*c)->screen].need_arrange = true;
return 0; return 0;
} }
@ -1213,9 +1279,11 @@ const struct luaL_reg awesome_client_meta[] =
{ "titlebar_get", luaA_client_titlebar_get }, { "titlebar_get", luaA_client_titlebar_get },
{ "name_get", luaA_client_name_get }, { "name_get", luaA_client_name_get },
{ "name_set", luaA_client_name_set }, { "name_set", luaA_client_name_set },
{ "screen_set", luaA_client_screen_set },
{ "screen_get", luaA_client_screen_get },
{ "border_set", luaA_client_border_set }, { "border_set", luaA_client_border_set },
{ "workspace_set", luaA_client_workspace_set }, { "tag", luaA_client_tag },
{ "workspace_get", luaA_client_workspace_get }, { "istagged", luaA_client_istagged },
{ "coords_get", luaA_client_coords_get }, { "coords_get", luaA_client_coords_get },
{ "coords_set", luaA_client_coords_set }, { "coords_set", luaA_client_coords_set },
{ "opacity_set", luaA_client_opacity_set }, { "opacity_set", luaA_client_opacity_set },

View File

@ -28,7 +28,7 @@
bool client_isvisible(client_t *, int); bool client_isvisible(client_t *, int);
client_t * client_getbywin(xcb_window_t); client_t * client_getbywin(xcb_window_t);
bool client_focus(client_t *); bool client_focus(client_t *, int);
void client_raise(client_t *); void client_raise(client_t *);
void client_ban(client_t *); void client_ban(client_t *);
void client_unban(client_t *); void client_unban(client_t *);

15
event.c
View File

@ -25,6 +25,7 @@
#include "screen.h" #include "screen.h"
#include "event.h" #include "event.h"
#include "tag.h"
#include "statusbar.h" #include "statusbar.h"
#include "window.h" #include "window.h"
#include "mouse.h" #include "mouse.h"
@ -33,7 +34,6 @@
#include "widget.h" #include "widget.h"
#include "titlebar.h" #include "titlebar.h"
#include "lua.h" #include "lua.h"
#include "workspace.h"
#include "layouts/tile.h" #include "layouts/tile.h"
#include "layouts/floating.h" #include "layouts/floating.h"
#include "common/xscreen.h" #include "common/xscreen.h"
@ -146,7 +146,7 @@ event_handle_buttonpress(void *data __attribute__ ((unused)),
if(ev->event_x >= w->area.x && ev->event_x < w->area.x + w->area.width if(ev->event_x >= w->area.x && ev->event_x < w->area.x + w->area.width
&& ev->event_y >= w->area.y && ev->event_y < w->area.y + w->area.height) && ev->event_y >= w->area.y && ev->event_y < w->area.y + w->area.height)
{ {
w->widget->button_press(w, ev, workspace_screen_get(workspace_client_get(c)), w->widget->button_press(w, ev, c->screen,
c->titlebar, AWESOME_TYPE_TITLEBAR); c->titlebar, AWESOME_TYPE_TITLEBAR);
return 0; return 0;
} }
@ -181,12 +181,9 @@ event_handle_configurerequest(void *data __attribute__ ((unused)),
{ {
client_t *c; client_t *c;
area_t geometry; area_t geometry;
workspace_t *ws;
if((c = client_getbywin(ev->window))) if((c = client_getbywin(ev->window)))
{ {
ws = workspace_client_get(c);
geometry = c->geometry; geometry = c->geometry;
if(ev->value_mask & XCB_CONFIG_WINDOW_X) if(ev->value_mask & XCB_CONFIG_WINDOW_X)
@ -201,11 +198,11 @@ event_handle_configurerequest(void *data __attribute__ ((unused)),
if(geometry.x != c->geometry.x || geometry.y != c->geometry.y if(geometry.x != c->geometry.x || geometry.y != c->geometry.y
|| geometry.width != c->geometry.width || geometry.height != c->geometry.height) || geometry.width != c->geometry.width || geometry.height != c->geometry.height)
{ {
if(c->isfloating || ws->layout == layout_floating) if(c->isfloating || layout_get_current(c->screen) == layout_floating)
client_resize(c, geometry, false); client_resize(c, geometry, false);
else else
{ {
ws->need_arrange = true; globalconf.screens[c->screen].need_arrange = true;
/* If we do not resize the client, at least tell it that it /* If we do not resize the client, at least tell it that it
* has its new configuration. That fixes at least * has its new configuration. That fixes at least
* gnome-terminal */ * gnome-terminal */
@ -466,7 +463,6 @@ event_handle_propertynotify(void *data __attribute__ ((unused)),
{ {
client_t *c; client_t *c;
xcb_window_t trans; xcb_window_t trans;
workspace_t *ws;
if(ev->state == XCB_PROPERTY_DELETE) if(ev->state == XCB_PROPERTY_DELETE)
return 0; /* ignore */ return 0; /* ignore */
@ -474,11 +470,10 @@ event_handle_propertynotify(void *data __attribute__ ((unused)),
{ {
if(ev->atom == WM_TRANSIENT_FOR) if(ev->atom == WM_TRANSIENT_FOR)
{ {
ws = workspace_client_get(c);
xutil_get_transient_for_hint(connection, c->win, &trans); xutil_get_transient_for_hint(connection, c->win, &trans);
if(!c->isfloating if(!c->isfloating
&& (c->isfloating = (client_getbywin(trans) != NULL))) && (c->isfloating = (client_getbywin(trans) != NULL)))
ws->need_arrange = true; globalconf.screens[c->screen].need_arrange = true;
} }
else if (ev->atom == WM_NORMAL_HINTS) else if (ev->atom == WM_NORMAL_HINTS)
client_updatesizehints(c); client_updatesizehints(c);

44
ewmh.c
View File

@ -24,7 +24,7 @@
#include <xcb/xcb_aux.h> #include <xcb/xcb_aux.h>
#include "ewmh.h" #include "ewmh.h"
#include "workspace.h" #include "tag.h"
#include "focus.h" #include "focus.h"
#include "screen.h" #include "screen.h"
#include "client.h" #include "client.h"
@ -188,9 +188,9 @@ void
ewmh_update_net_numbers_of_desktop(int phys_screen) ewmh_update_net_numbers_of_desktop(int phys_screen)
{ {
uint32_t count = 0; uint32_t count = 0;
workspace_t *workspace; tag_t *tag;
for(workspace = globalconf.workspaces; workspace; workspace = workspace->next) for(tag = globalconf.screens[phys_screen].tags; tag; tag = tag->next)
count++; count++;
xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
@ -202,14 +202,16 @@ void
ewmh_update_net_current_desktop(int phys_screen) ewmh_update_net_current_desktop(int phys_screen)
{ {
uint32_t count = 0; uint32_t count = 0;
workspace_t *workspace; tag_t *tag, **curtags = tags_get_current(phys_screen);
for(workspace = globalconf.workspaces; workspace; workspace = workspace->next) for(tag = globalconf.screens[phys_screen].tags; tag != curtags[0]; tag = tag->next)
count++; count++;
xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
xcb_aux_get_screen(globalconf.connection, phys_screen)->root, xcb_aux_get_screen(globalconf.connection, phys_screen)->root,
net_current_desktop, CARDINAL, 32, 1, &count); net_current_desktop, CARDINAL, 32, 1, &count);
p_delete(&curtags);
} }
void void
@ -217,14 +219,14 @@ ewmh_update_net_desktop_names(int phys_screen)
{ {
char buf[1024], *pos; char buf[1024], *pos;
ssize_t len, curr_size; ssize_t len, curr_size;
workspace_t *workspace; tag_t *tag;
pos = buf; pos = buf;
len = 0; len = 0;
for(workspace = globalconf.workspaces; workspace; workspace = workspace->next) for(tag = globalconf.screens[phys_screen].tags; tag; tag = tag->next)
{ {
curr_size = a_strlen(workspace->name); curr_size = a_strlen(tag->name);
a_strcpy(pos, sizeof(buf), workspace->name); a_strcpy(pos, sizeof(buf), tag->name);
pos += curr_size + 1; pos += curr_size + 1;
len += curr_size + 1; len += curr_size + 1;
} }
@ -238,7 +240,7 @@ void
ewmh_update_net_active_window(int phys_screen) ewmh_update_net_active_window(int phys_screen)
{ {
xcb_window_t win; xcb_window_t win;
client_t *sel = focus_client_getcurrent(globalconf.screens[phys_screen].workspace); client_t *sel = focus_get_current_client(phys_screen);
win = sel ? sel->win : XCB_NONE; win = sel ? sel->win : XCB_NONE;
@ -251,11 +253,12 @@ static void
ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set) ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set)
{ {
const uint32_t raise_window_val = XCB_STACK_MODE_ABOVE; const uint32_t raise_window_val = XCB_STACK_MODE_ABOVE;
int screen;
if(state == net_wm_state_sticky) if(state == net_wm_state_sticky)
{ {
/* \todo support for sticky */ tag_t *tag;
for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
tag_client(c, tag);
} }
else if(state == net_wm_state_skip_taskbar) else if(state == net_wm_state_skip_taskbar)
{ {
@ -287,8 +290,7 @@ ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set)
} }
else if(set == _NET_WM_STATE_ADD) else if(set == _NET_WM_STATE_ADD)
{ {
screen = workspace_screen_get(workspace_client_get(c)); geometry = screen_area_get(c->screen, NULL, &globalconf.screens[c->screen].padding);
geometry = screen_area_get(screen, NULL, &globalconf.screens[screen].padding);
/* save geometry */ /* save geometry */
c->m_geometry = c->geometry; c->m_geometry = c->geometry;
c->wasfloating = c->isfloating; c->wasfloating = c->isfloating;
@ -304,7 +306,7 @@ ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set)
c->noborder = true; c->noborder = true;
client_setfloating(c, true, LAYER_FULLSCREEN); client_setfloating(c, true, LAYER_FULLSCREEN);
} }
widget_invalidate_cache(WIDGET_CACHE_CLIENTS); widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
client_resize(c, geometry, false); client_resize(c, geometry, false);
xcb_configure_window(globalconf.connection, c->win, XCB_CONFIG_WINDOW_STACK_MODE, &raise_window_val); xcb_configure_window(globalconf.connection, c->win, XCB_CONFIG_WINDOW_STACK_MODE, &raise_window_val);
} }
@ -365,21 +367,17 @@ ewmh_process_client_message(xcb_client_message_event_t *ev)
{ {
client_t *c; client_t *c;
int screen; int screen;
unsigned int i;
workspace_t *ws;
if(ev->type == net_current_desktop) if(ev->type == net_current_desktop)
{
for(screen = 0; for(screen = 0;
screen < xcb_setup_roots_length(xcb_get_setup(globalconf.connection)); screen < xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
screen++) screen++)
if(ev->window == xcb_aux_get_screen(globalconf.connection, screen)->root)
{ {
for(i = 0, ws = globalconf.workspaces; i < ev->data.data32[0]; i++, ws = ws ->next); if(ev->window == xcb_aux_get_screen(globalconf.connection, screen)->root)
globalconf.screens[screen].workspace = ws; tag_view_only_byindex(screen, ev->data.data32[0]);
} }
}
else if(ev->type == net_close_window) if(ev->type == net_close_window)
{ {
if((c = client_getbywin(ev->window))) if((c = client_getbywin(ev->window)))
client_kill(c); client_kill(c);

21
focus.c
View File

@ -21,7 +21,7 @@
#include "focus.h" #include "focus.h"
#include "cnode.h" #include "cnode.h"
#include "workspace.h" #include "tag.h"
extern awesome_t globalconf; extern awesome_t globalconf;
@ -61,28 +61,33 @@ focus_client_delete(client_t *c)
} }
static client_t * static client_t *
focus_get_latest_client_for_workspace(workspace_t *ws, int nindex) focus_get_latest_client_for_tags(tag_t **t, int nindex)
{ {
client_node_t *node; client_node_t *node;
tag_t **tags;
int i = 0; int i = 0;
for(node = globalconf.focus; node; node = node->next) for(node = globalconf.focus; node; node = node->next)
if(node->client && !node->client->skip && !node->client->ishidden) if(node->client && !node->client->skip && !node->client->ishidden)
if(workspace_client_get(node->client) == ws) for(tags = t; *tags; tags++)
if(is_client_tagged(node->client, *tags))
if(i-- == nindex) if(i-- == nindex)
return node->client; return node->client;
return NULL; return NULL;
} }
/** Get the latest focused client on a workspace. /** Get the latest focused client on a screen.
* \param ws The workspace. * \param screen The virtual screen number.
* \return A pointer to an existing client. * \return A pointer to an existing client.
*/ */
client_t * client_t *
focus_client_getcurrent(workspace_t *ws) focus_get_current_client(int screen)
{ {
return focus_get_latest_client_for_workspace(ws, 0); tag_t **curtags = tags_get_current(screen);
client_t *sel = focus_get_latest_client_for_tags(curtags, 0);
p_delete(&curtags);
return sel;
} }
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -27,7 +27,7 @@
void focus_client_push(client_t *); void focus_client_push(client_t *);
void focus_client_append(client_t *); void focus_client_append(client_t *);
void focus_client_delete(client_t *); void focus_client_delete(client_t *);
client_t * focus_client_getcurrent(workspace_t *); client_t * focus_get_current_client(int);
#endif #endif
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -23,12 +23,13 @@
#include <xcb/xcb_atom.h> #include <xcb/xcb_atom.h>
#include <xcb/xcb_aux.h> #include <xcb/xcb_aux.h>
#include "tag.h"
#include "focus.h" #include "focus.h"
#include "widget.h" #include "widget.h"
#include "window.h" #include "window.h"
#include "client.h" #include "client.h"
#include "screen.h" #include "screen.h"
#include "workspace.h" #include "layouts/magnifier.h"
#include "layouts/tile.h" #include "layouts/tile.h"
#include "layouts/max.h" #include "layouts/max.h"
#include "layouts/fibonacci.h" #include "layouts/fibonacci.h"
@ -36,27 +37,26 @@
extern awesome_t globalconf; extern awesome_t globalconf;
/** Arrange windows following current selected layout. /** Arrange windows following current selected layout
* \param ws The workspace to arrange. * \param screen the screen to arrange
*/ */
static void static void
arrange(workspace_t *ws) arrange(int screen)
{ {
client_t *c; client_t *c;
int fscreen, screen = workspace_screen_get(ws), phys_screen = screen_virttophys(screen); layout_t *curlay = layout_get_current(screen);
int fscreen, phys_screen = screen_virttophys(screen);
xcb_query_pointer_cookie_t qp_c; xcb_query_pointer_cookie_t qp_c;
xcb_query_pointer_reply_t *qp_r; xcb_query_pointer_reply_t *qp_r;
workspace_t *cws;
for(c = globalconf.clients; c; c = c->next) for(c = globalconf.clients; c; c = c->next)
if((cws = workspace_client_get(c)) == ws && !c->ishidden)
{ {
screen_client_moveto(c, screen); if(!c->ishidden && client_isvisible(c, screen))
client_unban(c); client_unban(c);
}
/* we don't touch other screens windows */ /* we don't touch other screens windows */
else if(c->ishidden || workspace_screen_get(cws) == -1) else if(c->screen == screen)
client_ban(c); client_ban(c);
}
qp_c = xcb_query_pointer_unchecked(globalconf.connection, qp_c = xcb_query_pointer_unchecked(globalconf.connection,
xcb_aux_get_screen(globalconf.connection, xcb_aux_get_screen(globalconf.connection,
@ -81,25 +81,26 @@ arrange(workspace_t *ws)
/* if the mouse in on the same screen we just rearranged, and no /* if the mouse in on the same screen we just rearranged, and no
* client are currently focused, pick the first one in history */ * client are currently focused, pick the first one in history */
if(fscreen == screen if(fscreen == screen
&& (c = focus_client_getcurrent(ws))) && (c = focus_get_current_client(screen)))
client_focus(c); client_focus(c, screen);
} }
p_delete(&qp_r); p_delete(&qp_r);
} }
if(ws->layout) if(curlay)
ws->layout(ws); curlay(screen);
/* reset status */ /* reset status */
ws->need_arrange = false; globalconf.screens[screen].need_arrange = false;
/* call hook */ /* call hook */
luaA_workspace_userdata_new(ws); lua_pushnumber(globalconf.L, screen + 1);
luaA_dofunction(globalconf.L, globalconf.hooks.arrange, 1); luaA_dofunction(globalconf.L, globalconf.hooks.arrange, 1);
} }
/** Refresh the screens disposition. /** Refresh the screen disposition
* \return true if the screen was arranged, false otherwise
*/ */
void void
layout_refresh(void) layout_refresh(void)
@ -107,8 +108,25 @@ layout_refresh(void)
int screen; int screen;
for(screen = 0; screen < globalconf.screens_info->nscreen; screen++) for(screen = 0; screen < globalconf.screens_info->nscreen; screen++)
if(globalconf.screens[screen].workspace && globalconf.screens[screen].workspace->need_arrange) if(globalconf.screens[screen].need_arrange)
arrange(globalconf.screens[screen].workspace); arrange(screen);
}
/** Get current layout used on screen.
* \param screen Virtual screen number.
* \return layout used on that screen
*/
layout_t *
layout_get_current(int screen)
{
layout_t *l = NULL;
tag_t **curtags = tags_get_current(screen);
if(curtags[0])
l = curtags[0]->layout;
p_delete(&curtags);
return l;
} }
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -25,6 +25,9 @@
#include "common/list.h" #include "common/list.h"
#include "common/util.h" #include "common/util.h"
typedef void (layout_t)(int);
layout_t * layout_get_current(int);
void layout_refresh(void); void layout_refresh(void);
#endif #endif

View File

@ -20,19 +20,18 @@
*/ */
#include "screen.h" #include "screen.h"
#include "workspace.h" #include "tag.h"
#include "client.h" #include "client.h"
#include "layouts/fibonacci.h" #include "layouts/fibonacci.h"
extern awesome_t globalconf; extern awesome_t globalconf;
static void static void
layout_fibonacci(workspace_t *ws, int shape) layout_fibonacci(int screen, int shape)
{ {
int n = 0, i = 0; int n = 0, i = 0;
client_t *c; client_t *c;
area_t geometry, area; area_t geometry, area;
int screen = workspace_screen_get(ws);
geometry = area = screen_area_get(screen, geometry = area = screen_area_get(screen,
globalconf.screens[screen].statusbar, globalconf.screens[screen].statusbar,
&globalconf.screens[screen].padding); &globalconf.screens[screen].padding);
@ -89,15 +88,15 @@ layout_fibonacci(workspace_t *ws, int shape)
} }
void void
layout_spiral(workspace_t *ws) layout_spiral(int screen)
{ {
layout_fibonacci(ws, 0); layout_fibonacci(screen, 0);
} }
void void
layout_dwindle(workspace_t *ws) layout_dwindle(int screen)
{ {
layout_fibonacci(ws, 1); layout_fibonacci(screen, 1);
} }
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -20,16 +20,15 @@
*/ */
#include "client.h" #include "client.h"
#include "workspace.h" #include "tag.h"
#include "layouts/floating.h" #include "layouts/floating.h"
extern awesome_t globalconf; extern awesome_t globalconf;
void void
layout_floating(workspace_t *ws) layout_floating(int screen)
{ {
client_t *c; client_t *c;
int screen = workspace_screen_get(ws);
for(c = globalconf.clients; c; c = c->next) for(c = globalconf.clients; c; c = c->next)
if(client_isvisible(c, screen) && !c->ismax) if(client_isvisible(c, screen) && !c->ismax)

View File

@ -20,7 +20,7 @@
*/ */
#include "client.h" #include "client.h"
#include "workspace.h" #include "tag.h"
#include "screen.h" #include "screen.h"
#include "focus.h" #include "focus.h"
#include "layouts/magnifier.h" #include "layouts/magnifier.h"
@ -28,16 +28,16 @@
extern awesome_t globalconf; extern awesome_t globalconf;
void void
layout_magnifier(workspace_t *ws) layout_magnifier(int screen)
{ {
int n = 0; int n = 0;
client_t *c, *focus; client_t *c, *focus;
int screen = workspace_screen_get(ws); tag_t **curtags = tags_get_current(screen);
area_t geometry, area = screen_area_get(screen, area_t geometry, area = screen_area_get(screen,
globalconf.screens[screen].statusbar, globalconf.screens[screen].statusbar,
&globalconf.screens[screen].padding); &globalconf.screens[screen].padding);
focus = focus_client_getcurrent(ws); focus = focus_get_current_client(screen);
/* If focused window is not tiled, take the first one which is tiled. */ /* If focused window is not tiled, take the first one which is tiled. */
if(!IS_TILED(focus, screen)) if(!IS_TILED(focus, screen))
@ -45,10 +45,10 @@ layout_magnifier(workspace_t *ws)
/* No windows is tiled, nothing to do. */ /* No windows is tiled, nothing to do. */
if(!focus) if(!focus)
return; goto bailout;
geometry.width = area.width * ws->mwfact; geometry.width = area.width * curtags[0]->mwfact;
geometry.height = area.height * ws->mwfact; geometry.height = area.height * curtags[0]->mwfact;
geometry.x = area.x + (area.width - geometry.width) / 2; geometry.x = area.x + (area.width - geometry.width) / 2;
geometry.y = area.y + (area.height - geometry.height) / 2; geometry.y = area.y + (area.height - geometry.height) / 2;
client_resize(focus, geometry, globalconf.resize_hints); client_resize(focus, geometry, globalconf.resize_hints);
@ -62,7 +62,7 @@ layout_magnifier(workspace_t *ws)
/* No other clients. */ /* No other clients. */
if(!n) if(!n)
return; goto bailout;
geometry.x = area.x; geometry.x = area.x;
geometry.y = area.y; geometry.y = area.y;
@ -81,5 +81,8 @@ layout_magnifier(workspace_t *ws)
geometry.width += 2 * c->border; geometry.width += 2 * c->border;
geometry.y += geometry.height; geometry.y += geometry.height;
} }
bailout:
p_delete(&curtags);
} }
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -19,7 +19,7 @@
* *
*/ */
#include "workspace.h" #include "tag.h"
#include "screen.h" #include "screen.h"
#include "client.h" #include "client.h"
#include "focus.h" #include "focus.h"
@ -28,10 +28,9 @@
extern awesome_t globalconf; extern awesome_t globalconf;
void void
layout_max(workspace_t *ws) layout_max(int screen)
{ {
client_t *c, *focus; client_t *c, *focus;
int screen = workspace_screen_get(ws);
area_t area = screen_area_get(screen, area_t area = screen_area_get(screen,
globalconf.screens[screen].statusbar, globalconf.screens[screen].statusbar,
&globalconf.screens[screen].padding); &globalconf.screens[screen].padding);
@ -46,7 +45,7 @@ layout_max(workspace_t *ws)
area.height += 2 * c->border; area.height += 2 * c->border;
} }
if((focus = focus_client_getcurrent(ws)) if((focus = focus_get_current_client(screen))
&& IS_TILED(focus, screen)) && IS_TILED(focus, screen))
client_raise(focus); client_raise(focus);
} }

View File

@ -22,7 +22,7 @@
#include <stdio.h> #include <stdio.h>
#include "screen.h" #include "screen.h"
#include "workspace.h" #include "tag.h"
#include "client.h" #include "client.h"
#include "layouts/tile.h" #include "layouts/tile.h"
#include "common/util.h" #include "common/util.h"
@ -30,18 +30,17 @@
extern awesome_t globalconf; extern awesome_t globalconf;
static void static void
_tile(workspace_t *ws, const position_t position) _tile(int screen, const position_t position)
{ {
/* windows area geometry */ /* windows area geometry */
int wah = 0, waw = 0, wax = 0, way = 0; int wah = 0, waw = 0, wax = 0, way = 0;
/* master size */ /* master size */
unsigned int mw = 0, mh = 0; unsigned int mw = 0, mh = 0;
int n, i, masterwin = 0, otherwin = 0; int n, i, masterwin = 0, otherwin = 0;
int screen, real_ncol = 1, win_by_col = 1, current_col = 0; int real_ncol = 1, win_by_col = 1, current_col = 0;
area_t area, geometry = { 0, 0, 0, 0, NULL, NULL }; area_t area, geometry = { 0, 0, 0, 0, NULL, NULL };
client_t *c; client_t *c;
tag_t **curtags = tags_get_current(screen);
screen = workspace_screen_get(ws);
area = screen_area_get(screen, area = screen_area_get(screen,
globalconf.screens[screen].statusbar, globalconf.screens[screen].statusbar,
@ -56,34 +55,34 @@ _tile(workspace_t *ws, const position_t position)
wax = area.x; wax = area.x;
way = area.y; way = area.y;
masterwin = MIN(n, ws->nmaster); masterwin = MIN(n, curtags[0]->nmaster);
otherwin = MAX(n - masterwin, 0); otherwin = MAX(n - masterwin, 0);
if(ws->nmaster) if(curtags[0]->nmaster)
switch(position) switch(position)
{ {
case Right: case Right:
case Left: case Left:
mh = masterwin ? wah / masterwin : wah; mh = masterwin ? wah / masterwin : wah;
mw = otherwin ? waw * ws->mwfact : waw; mw = otherwin ? waw * curtags[0]->mwfact : waw;
break; break;
default: default:
mh = otherwin ? wah * ws->mwfact : wah; mh = otherwin ? wah * curtags[0]->mwfact : wah;
mw = masterwin ? waw / masterwin : waw; mw = masterwin ? waw / masterwin : waw;
break; break;
} }
else else
mh = mw = 0; mh = mw = 0;
real_ncol = ws->ncol > 0 ? MIN(otherwin, ws->ncol) : MIN(otherwin, 1); real_ncol = curtags[0]->ncol > 0 ? MIN(otherwin, curtags[0]->ncol) : MIN(otherwin, 1);
for(i = 0, c = globalconf.clients; c; c = c->next) for(i = 0, c = globalconf.clients; c; c = c->next)
{ {
if(!IS_TILED(c, screen)) if(!IS_TILED(c, screen))
continue; continue;
if(i < ws->nmaster) if(i < curtags[0]->nmaster)
{ {
switch(position) switch(position)
{ {
@ -117,8 +116,8 @@ _tile(workspace_t *ws, const position_t position)
if(real_ncol) if(real_ncol)
win_by_col = otherwin / real_ncol; win_by_col = otherwin / real_ncol;
if((i - ws->nmaster) if((i - curtags[0]->nmaster)
&& (i - ws->nmaster) % win_by_col == 0 && (i - curtags[0]->nmaster) % win_by_col == 0
&& current_col < real_ncol - 1) && current_col < real_ncol - 1)
current_col++; current_col++;
@ -134,10 +133,10 @@ _tile(workspace_t *ws, const position_t position)
geometry.width = (waw - mw) / real_ncol - 2 * c->border; geometry.width = (waw - mw) / real_ncol - 2 * c->border;
if(i == ws->nmaster || otherwin <= real_ncol || (i - ws->nmaster) % win_by_col == 0) if(i == curtags[0]->nmaster || otherwin <= real_ncol || (i - curtags[0]->nmaster) % win_by_col == 0)
geometry.y = way; geometry.y = way;
else else
geometry.y = way + ((i - ws->nmaster) % win_by_col) * (geometry.height + 2 * c->border); geometry.y = way + ((i - curtags[0]->nmaster) % win_by_col) * (geometry.height + 2 * c->border);
geometry.x = wax + current_col * (geometry.width + 2 * c->border); geometry.x = wax + current_col * (geometry.width + 2 * c->border);
@ -153,10 +152,10 @@ _tile(workspace_t *ws, const position_t position)
geometry.height = (wah - mh) / real_ncol - 2 * c->border; geometry.height = (wah - mh) / real_ncol - 2 * c->border;
if(i == ws->nmaster || otherwin <= real_ncol || (i - ws->nmaster) % win_by_col == 0) if(i == curtags[0]->nmaster || otherwin <= real_ncol || (i - curtags[0]->nmaster) % win_by_col == 0)
geometry.x = wax; geometry.x = wax;
else else
geometry.x = wax + ((i - ws->nmaster) % win_by_col) * (geometry.width + 2 * c->border); geometry.x = wax + ((i - curtags[0]->nmaster) % win_by_col) * (geometry.width + 2 * c->border);
geometry.y = way + current_col * (geometry.height + 2 * c->border); geometry.y = way + current_col * (geometry.height + 2 * c->border);
@ -167,30 +166,32 @@ _tile(workspace_t *ws, const position_t position)
} }
i++; i++;
} }
p_delete(&curtags);
} }
void void
layout_tile(workspace_t *ws) layout_tile(int screen)
{ {
_tile(ws, Right); _tile(screen, Right);
} }
void void
layout_tileleft(workspace_t *ws) layout_tileleft(int screen)
{ {
_tile(ws, Left); _tile(screen, Left);
} }
void void
layout_tilebottom(workspace_t *ws) layout_tilebottom(int screen)
{ {
_tile(ws, Bottom); _tile(screen, Bottom);
} }
void void
layout_tiletop(workspace_t *ws) layout_tiletop(int screen)
{ {
_tile(ws, Top); _tile(screen, Top);
} }
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

28
lua.c
View File

@ -32,7 +32,7 @@
#include "config.h" #include "config.h"
#include "structs.h" #include "structs.h"
#include "lua.h" #include "lua.h"
#include "workspace.h" #include "tag.h"
#include "client.h" #include "client.h"
#include "window.h" #include "window.h"
#include "statusbar.h" #include "statusbar.h"
@ -49,8 +49,8 @@ extern const struct luaL_reg awesome_client_methods[];
extern const struct luaL_reg awesome_client_meta[]; extern const struct luaL_reg awesome_client_meta[];
extern const struct luaL_reg awesome_titlebar_methods[]; extern const struct luaL_reg awesome_titlebar_methods[];
extern const struct luaL_reg awesome_titlebar_meta[]; extern const struct luaL_reg awesome_titlebar_meta[];
extern const struct luaL_reg awesome_workspace_methods[]; extern const struct luaL_reg awesome_tag_methods[];
extern const struct luaL_reg awesome_workspace_meta[]; extern const struct luaL_reg awesome_tag_meta[];
extern const struct luaL_reg awesome_widget_methods[]; extern const struct luaL_reg awesome_widget_methods[];
extern const struct luaL_reg awesome_widget_meta[]; extern const struct luaL_reg awesome_widget_meta[];
extern const struct luaL_reg awesome_statusbar_methods[]; extern const struct luaL_reg awesome_statusbar_methods[];
@ -191,17 +191,16 @@ luaA_screen_count(lua_State *L)
return 1; return 1;
} }
/** Get the workspace displayed on a screen. /** Give the focus to a screen.
* \param A screen number. * \param A screen number
*/ */
static int static int
luaA_screen_workspace_get(lua_State *L) luaA_screen_focus(lua_State *L)
{ {
/* Our table begin at 0, Lua begins at 1 */ /* Our table begin at 0, Lua begins at 1 */
int screen = luaL_checknumber(L, 1) - 1; int screen = luaL_checknumber(L, 1) - 1;
luaA_checkscreen(screen); luaA_checkscreen(screen);
if(globalconf.screens[screen].workspace) client_focus(NULL, screen);
return luaA_workspace_userdata_new(globalconf.screens[screen].workspace);
return 0; return 0;
} }
@ -427,7 +426,7 @@ luaA_init(void)
{ {
{ "coords_get", luaA_screen_coords_get }, { "coords_get", luaA_screen_coords_get },
{ "count", luaA_screen_count }, { "count", luaA_screen_count },
{ "workspace_get", luaA_screen_workspace_get }, { "focus", luaA_screen_focus },
{ NULL, NULL } { NULL, NULL }
}; };
static const struct luaL_reg awesome_hooks_lib[] = static const struct luaL_reg awesome_hooks_lib[] =
@ -459,8 +458,8 @@ luaA_init(void)
/* Export hooks lib */ /* Export hooks lib */
luaL_register(L, "mouse", awesome_mouse_lib); luaL_register(L, "mouse", awesome_mouse_lib);
/* Export workspace */ /* Export tag */
luaA_openlib(L, "workspace", awesome_workspace_methods, awesome_workspace_meta); luaA_openlib(L, "tag", awesome_tag_methods, awesome_tag_meta);
/* Export statusbar */ /* Export statusbar */
luaA_openlib(L, "statusbar", awesome_statusbar_methods, awesome_statusbar_meta); luaA_openlib(L, "statusbar", awesome_statusbar_methods, awesome_statusbar_meta);
@ -492,13 +491,18 @@ luaA_init(void)
bool bool
luaA_parserc(const char* rcfile) luaA_parserc(const char* rcfile)
{ {
int screen;
if(luaL_dofile(globalconf.L, rcfile)) if(luaL_dofile(globalconf.L, rcfile))
{ {
fprintf(stderr, "%s\n", lua_tostring(globalconf.L, -1)); fprintf(stderr, "%s\n", lua_tostring(globalconf.L, -1));
return false; return false;
} }
/* \todo Assure there's at least one workspace */ /* Assure there's at least one tag */
for(screen = 0; screen < globalconf.screens_info->nscreen; screen++)
if(!globalconf.screens[screen].tags)
tag_append_to_screen(tag_new("default", layout_tile, 0.5, 1, 0), screen);
return true; return true;
} }

129
mouse.c
View File

@ -27,7 +27,7 @@
#include "mouse.h" #include "mouse.h"
#include "screen.h" #include "screen.h"
#include "workspace.h" #include "tag.h"
#include "event.h" #include "event.h"
#include "client.h" #include "client.h"
#include "titlebar.h" #include "titlebar.h"
@ -126,12 +126,11 @@ static area_t
mouse_snapclient(client_t *c, area_t geometry, int snap) mouse_snapclient(client_t *c, area_t geometry, int snap)
{ {
client_t *snapper; client_t *snapper;
int screen = workspace_screen_get(workspace_client_get(c));
area_t snapper_geometry; area_t snapper_geometry;
area_t screen_geometry = area_t screen_geometry =
screen_area_get(screen, screen_area_get(c->screen,
globalconf.screens[screen].statusbar, globalconf.screens[c->screen].statusbar,
&globalconf.screens[screen].padding); &globalconf.screens[c->screen].padding);
geometry = titlebar_geometry_add(c->titlebar, geometry); geometry = titlebar_geometry_add(c->titlebar, geometry);
geometry.width += 2 * c->border; geometry.width += 2 * c->border;
@ -141,7 +140,7 @@ mouse_snapclient(client_t *c, area_t geometry, int snap)
mouse_snapclienttogeometry_inside(geometry, screen_geometry, snap); mouse_snapclienttogeometry_inside(geometry, screen_geometry, snap);
for(snapper = globalconf.clients; snapper; snapper = snapper->next) for(snapper = globalconf.clients; snapper; snapper = snapper->next)
if(snapper != c && client_isvisible(c, screen)) if(snapper != c && client_isvisible(c, c->screen))
{ {
snapper_geometry = snapper->geometry; snapper_geometry = snapper->geometry;
snapper_geometry.width += 2 * c->border; snapper_geometry.width += 2 * c->border;
@ -297,9 +296,10 @@ mouse_warp_pointer(xcb_window_t window, int x, int y)
static void static void
mouse_client_move(client_t *c, int snap) mouse_client_move(client_t *c, int snap)
{ {
int ocx, ocy, newscreen;
area_t geometry; area_t geometry;
client_t *target; client_t *target;
workspace_t *ws = workspace_client_get(c); layout_t *layout;
simple_window_t *sw = NULL; simple_window_t *sw = NULL;
draw_context_t *ctx; draw_context_t *ctx;
xcb_generic_event_t *ev = NULL; xcb_generic_event_t *ev = NULL;
@ -309,8 +309,8 @@ mouse_client_move(client_t *c, int snap)
xcb_query_pointer_reply_t *query_pointer_r = NULL, *mquery_pointer_r = NULL; xcb_query_pointer_reply_t *query_pointer_r = NULL, *mquery_pointer_r = NULL;
xcb_query_pointer_cookie_t query_pointer_c; xcb_query_pointer_cookie_t query_pointer_c;
xcb_screen_t *s; xcb_screen_t *s;
int ocx, ocy, newscreen, screen = workspace_screen_get(ws);
layout = layout_get_current(c->screen);
s = xcb_aux_get_screen(globalconf.connection, c->phys_screen); s = xcb_aux_get_screen(globalconf.connection, c->phys_screen);
/* Send pointer requests */ /* Send pointer requests */
@ -334,16 +334,18 @@ mouse_client_move(client_t *c, int snap)
query_pointer_r = xcb_query_pointer_reply(globalconf.connection, query_pointer_c, NULL); query_pointer_r = xcb_query_pointer_reply(globalconf.connection, query_pointer_c, NULL);
if(c->isfloating || ws->layout == layout_floating) if(c->isfloating || layout == layout_floating)
{ {
sw = mouse_resizebar_new(c->phys_screen, c->border, c->geometry, &ctx); sw = mouse_resizebar_new(c->phys_screen, c->border, c->geometry, &ctx);
xcb_aux_sync(globalconf.connection); xcb_aux_sync(globalconf.connection);
} }
while(true) while(true)
{
/* XMaskEvent allows to retrieve only specified events from /* XMaskEvent allows to retrieve only specified events from
* the queue and requeue the other events... */ * the queue and requeue the other events... */
while(ev || (ev = xcb_wait_for_event(globalconf.connection))) while(ev || (ev = xcb_wait_for_event(globalconf.connection)))
{
switch((ev->response_type & 0x7f)) switch((ev->response_type & 0x7f))
{ {
case XCB_BUTTON_RELEASE: case XCB_BUTTON_RELEASE:
@ -357,7 +359,7 @@ mouse_client_move(client_t *c, int snap)
p_delete(&ev); p_delete(&ev);
return; return;
case XCB_MOTION_NOTIFY: case XCB_MOTION_NOTIFY:
if(c->isfloating || ws->layout == layout_floating) if(c->isfloating || layout == layout_floating)
{ {
ev_motion = (xcb_motion_notify_event_t *) ev; ev_motion = (xcb_motion_notify_event_t *) ev;
@ -365,21 +367,6 @@ mouse_client_move(client_t *c, int snap)
geometry.y = ocy + (ev_motion->event_y - query_pointer_r->root_y); geometry.y = ocy + (ev_motion->event_y - query_pointer_r->root_y);
geometry = mouse_snapclient(c, geometry, snap); geometry = mouse_snapclient(c, geometry, snap);
if((newscreen = screen_get_bycoord(globalconf.screens_info, screen,
geometry.x, geometry.y)) != screen)
{
if((ws = globalconf.screens[newscreen].workspace))
{
screen = workspace_screen_get(ws);
workspace_client_set(c, ws);
}
else
{
p_delete(&ev);
break;
}
}
c->ismoving = true; c->ismoving = true;
client_resize(c, geometry, false); client_resize(c, geometry, false);
c->ismoving = false; c->ismoving = false;
@ -393,24 +380,20 @@ mouse_client_move(client_t *c, int snap)
{ {
query_pointer_c = xcb_query_pointer_unchecked(globalconf.connection, s->root); query_pointer_c = xcb_query_pointer_unchecked(globalconf.connection, s->root);
mquery_pointer_r = xcb_query_pointer_reply(globalconf.connection, query_pointer_c, NULL); mquery_pointer_r = xcb_query_pointer_reply(globalconf.connection, query_pointer_c, NULL);
if((newscreen = screen_get_bycoord(globalconf.screens_info, if((newscreen = screen_get_bycoord(globalconf.screens_info, c->screen,
screen,
mquery_pointer_r->root_x, mquery_pointer_r->root_x,
mquery_pointer_r->root_y)) != screen mquery_pointer_r->root_y)) != c->screen)
&& globalconf.screens[newscreen].workspace)
{ {
ws->need_arrange = true; screen_client_moveto(c, newscreen, true);
ws = globalconf.screens[newscreen].workspace; globalconf.screens[c->screen].need_arrange = true;
screen = workspace_screen_get(ws); globalconf.screens[newscreen].need_arrange = true;
workspace_client_set(c, ws);
ws->need_arrange = true;
layout_refresh(); layout_refresh();
} }
if((target = client_getbywin(mquery_pointer_r->child)) if((target = client_getbywin(mquery_pointer_r->child))
&& target != c && !target->isfloating) && target != c && !target->isfloating)
{ {
client_list_swap(&globalconf.clients, c, target); client_list_swap(&globalconf.clients, c, target);
ws->need_arrange = true; globalconf.screens[c->screen].need_arrange = true;
layout_refresh(); layout_refresh();
} }
p_delete(&mquery_pointer_r); p_delete(&mquery_pointer_r);
@ -426,6 +409,8 @@ mouse_client_move(client_t *c, int snap)
break; break;
} }
} }
}
}
/** Utility function to help with mouse-dragging /** Utility function to help with mouse-dragging
@ -592,57 +577,62 @@ mouse_client_resize_floating(client_t *c, corner_t corner)
} }
/** Resize the master column/row of a tiled layout /** Resize the master column/row of a tiled layout
* \param c A client on the workspace/layout to resize. * \param c A client on the tag/layout to resize.
*/ */
static void static void
mouse_client_resize_tiled(client_t *c) mouse_client_resize_tiled(client_t *c)
{ {
xcb_screen_t *xscreen; xcb_screen_t *screen;
/* screen area modulo statusbar */ /* screen area modulo statusbar */
area_t area; area_t area;
/* current workspace */ /* current tag */
workspace_t *ws = workspace_client_get(c); tag_t *tag;
int mouse_x, mouse_y, screen = workspace_screen_get(ws); /* current layout */
layout_t *layout;
int mouse_x, mouse_y;
size_t cursor = CurResize; size_t cursor = CurResize;
xscreen = xcb_aux_get_screen(globalconf.connection, c->phys_screen); screen = xcb_aux_get_screen(globalconf.connection, c->phys_screen);
tag = tags_get_current(c->screen)[0];
layout = tag->layout;
area = screen_area_get(screen, area = screen_area_get(tag->screen,
globalconf.screens[screen].statusbar, globalconf.screens[tag->screen].statusbar,
&globalconf.screens[screen].padding); &globalconf.screens[tag->screen].padding);
mouse_query_pointer(xscreen->root, &mouse_x, &mouse_y); mouse_query_pointer(screen->root, &mouse_x, &mouse_y);
/* select initial pointer position */ /* select initial pointer position */
if(ws->layout == layout_tile) if(layout == layout_tile)
{ {
mouse_x = area.x + area.width * ws->mwfact; mouse_x = area.x + area.width * tag->mwfact;
cursor = CurResizeH; cursor = CurResizeH;
} }
else if(ws->layout == layout_tileleft) else if(layout == layout_tileleft)
{ {
mouse_x = area.x + area.width * (1. - ws->mwfact); mouse_x = area.x + area.width * (1. - tag->mwfact);
cursor = CurResizeH; cursor = CurResizeH;
} }
else if(ws->layout == layout_tilebottom) else if(layout == layout_tilebottom)
{ {
mouse_y = area.y + area.height * ws->mwfact; mouse_y = area.y + area.height * tag->mwfact;
cursor = CurResizeV; cursor = CurResizeV;
} }
else if(ws->layout == layout_tiletop) else if(layout == layout_tiletop)
{ {
mouse_y = area.y + area.height * (1. - ws->mwfact); mouse_y = area.y + area.height * (1. - tag->mwfact);
cursor = CurResizeV; cursor = CurResizeV;
} }
else else
return; return;
/* grab the pointer */ /* grab the pointer */
if(!mouse_grab_pointer(xscreen->root, cursor)) if(!mouse_grab_pointer(screen->root, cursor))
return; return;
/* set pointer to the moveable border */ /* set pointer to the moveable border */
mouse_warp_pointer(xscreen->root, mouse_x, mouse_y); mouse_warp_pointer(screen->root, mouse_x, mouse_y);
xcb_aux_sync(globalconf.connection); xcb_aux_sync(globalconf.connection);
@ -655,20 +645,20 @@ mouse_client_resize_tiled(client_t *c)
fact_x = (double) (mouse_x - area.x) / area.width; fact_x = (double) (mouse_x - area.x) / area.width;
fact_y = (double) (mouse_y - area.y) / area.height; fact_y = (double) (mouse_y - area.y) / area.height;
if(ws->layout == layout_tile) if(layout == layout_tile)
mwfact = fact_x; mwfact = fact_x;
else if(ws->layout == layout_tileleft) else if(layout == layout_tileleft)
mwfact = 1. - fact_x; mwfact = 1. - fact_x;
else if(ws->layout == layout_tilebottom) else if(layout == layout_tilebottom)
mwfact = fact_y; mwfact = fact_y;
else if(ws->layout == layout_tiletop) else if(layout == layout_tiletop)
mwfact = 1. - fact_y; mwfact = 1. - fact_y;
/* refresh layout */ /* refresh layout */
if(fabs(ws->mwfact - mwfact) >= 0.01) if(fabs(tag->mwfact - mwfact) >= 0.01)
{ {
ws->mwfact = mwfact; tag->mwfact = mwfact;
ws->need_arrange = true; globalconf.screens[tag->screen].need_arrange = true;
layout_refresh(); layout_refresh();
xcb_aux_sync(globalconf.connection); xcb_aux_sync(globalconf.connection);
} }
@ -689,13 +679,16 @@ static void
mouse_client_resize(client_t *c, corner_t corner) mouse_client_resize(client_t *c, corner_t corner)
{ {
int n, screen; int n, screen;
workspace_t *ws = workspace_client_get(c); tag_t **curtags;
layout_t *layout;
xcb_screen_t *s; xcb_screen_t *s;
curtags = tags_get_current(c->screen);
layout = curtags[0]->layout;
s = xcb_aux_get_screen(globalconf.connection, c->phys_screen); s = xcb_aux_get_screen(globalconf.connection, c->phys_screen);
/* only handle floating and tiled layouts */ /* only handle floating and tiled layouts */
if(ws->layout == layout_floating || c->isfloating) if(layout == layout_floating || c->isfloating)
{ {
if(c->isfixed) if(c->isfixed)
return; return;
@ -704,16 +697,16 @@ mouse_client_resize(client_t *c, corner_t corner)
mouse_client_resize_floating(c, corner); mouse_client_resize_floating(c, corner);
} }
else if (ws->layout == layout_tile || ws->layout == layout_tileleft else if (layout == layout_tile || layout == layout_tileleft
|| ws->layout == layout_tilebottom || ws->layout == layout_tiletop) || layout == layout_tilebottom || layout == layout_tiletop)
{ {
screen = workspace_screen_get(ws); screen = c->screen;
for(n = 0, c = globalconf.clients; c; c = c->next) for(n = 0, c = globalconf.clients; c; c = c->next)
if(IS_TILED(c, screen)) if(IS_TILED(c, screen))
n++; n++;
/* only masters on this screen? */ /* only masters on this screen? */
if(n <= ws->nmaster) return; if(n <= curtags[0]->nmaster) return;
/* no tiled clients on this screen? */ /* no tiled clients on this screen? */
for(c = globalconf.clients; c && !IS_TILED(c, screen); c = c->next); for(c = globalconf.clients; c && !IS_TILED(c, screen); c = c->next);

View File

@ -26,7 +26,6 @@
#include "screen.h" #include "screen.h"
#include "client.h" #include "client.h"
#include "titlebar.h" #include "titlebar.h"
#include "workspace.h"
#include "layouts/floating.h" #include "layouts/floating.h"
extern awesome_t globalconf; extern awesome_t globalconf;
@ -72,21 +71,21 @@ placement_smart(client_t *c)
area_t newgeometry = { 0, 0, 0, 0, NULL, NULL }; area_t newgeometry = { 0, 0, 0, 0, NULL, NULL };
area_t *screen_geometry, *arealist = NULL, *r; area_t *screen_geometry, *arealist = NULL, *r;
bool found = false; bool found = false;
workspace_t *ws = workspace_client_get(c); layout_t *layout;
int screen = workspace_screen_get(ws);
screen_geometry = p_new(area_t, 1); screen_geometry = p_new(area_t, 1);
*screen_geometry = screen_area_get(screen, *screen_geometry = screen_area_get(c->screen,
globalconf.screens[screen].statusbar, globalconf.screens[c->screen].statusbar,
&globalconf.screens[screen].padding); &globalconf.screens[c->screen].padding);
layout = layout_get_current(c->screen);
area_list_push(&arealist, screen_geometry); area_list_push(&arealist, screen_geometry);
for(client = globalconf.clients; client; client = client->next) for(client = globalconf.clients; client; client = client->next)
if((client->isfloating || ws->layout == layout_floating) if((client->isfloating || layout == layout_floating)
&& client_isvisible(client, screen)) && client_isvisible(client, c->screen))
{ {
newgeometry = client->f_geometry; newgeometry = client->f_geometry;
newgeometry.width += 2 * client->border; newgeometry.width += 2 * client->border;
@ -120,7 +119,7 @@ placement_smart(client_t *c)
newgeometry.height = c->f_geometry.height; newgeometry.height = c->f_geometry.height;
newgeometry = titlebar_geometry_add(c->titlebar, newgeometry); newgeometry = titlebar_geometry_add(c->titlebar, newgeometry);
newgeometry = placement_fix_offscreen(newgeometry, screen, c->border); newgeometry = placement_fix_offscreen(newgeometry, c->screen, c->border);
newgeometry = titlebar_geometry_remove(c->titlebar, newgeometry); newgeometry = titlebar_geometry_remove(c->titlebar, newgeometry);
area_list_wipe(&arealist); area_list_wipe(&arealist);
@ -134,7 +133,6 @@ placement_under_mouse(client_t *c)
xcb_query_pointer_cookie_t qp_c; xcb_query_pointer_cookie_t qp_c;
xcb_query_pointer_reply_t *qp_r; xcb_query_pointer_reply_t *qp_r;
area_t finalgeometry = c->f_geometry; area_t finalgeometry = c->f_geometry;
int screen = workspace_screen_get(workspace_client_get(c));
qp_c = xcb_query_pointer(globalconf.connection, qp_c = xcb_query_pointer(globalconf.connection,
xcb_aux_get_screen(globalconf.connection, c->phys_screen)->root); xcb_aux_get_screen(globalconf.connection, c->phys_screen)->root);
@ -147,7 +145,7 @@ placement_under_mouse(client_t *c)
} }
finalgeometry = titlebar_geometry_add(c->titlebar, finalgeometry); finalgeometry = titlebar_geometry_add(c->titlebar, finalgeometry);
finalgeometry = placement_fix_offscreen(finalgeometry, screen, c->border); finalgeometry = placement_fix_offscreen(finalgeometry, c->screen, c->border);
finalgeometry = titlebar_geometry_remove(c->titlebar, finalgeometry); finalgeometry = titlebar_geometry_remove(c->titlebar, finalgeometry);
return finalgeometry; return finalgeometry;

View File

@ -25,9 +25,9 @@
#include <xcb/xcb_aux.h> #include <xcb/xcb_aux.h>
#include "screen.h" #include "screen.h"
#include "tag.h"
#include "focus.h" #include "focus.h"
#include "client.h" #include "client.h"
#include "workspace.h"
#include "layouts/floating.h" #include "layouts/floating.h"
extern awesome_t globalconf; extern awesome_t globalconf;
@ -121,25 +121,33 @@ screen_virttophys(int screen)
/** Move a client to a virtual screen. /** Move a client to a virtual screen.
* \param c The client to move. * \param c The client to move.
* \param new_screen The new screen. * \param new_screen The destinatiuon screen number.
* \param doresize Set to true if we also move the client to the new x and
* y of the new screen.
*/ */
void void
screen_client_moveto(client_t *c, int new_screen) screen_client_moveto(client_t *c, int new_screen, bool doresize)
{ {
area_t from, to, new_geometry, new_f_geometry; tag_t *tag;
int old_screen; int old_screen = c->screen;
area_t from, to;
old_screen = screen_get_bycoord(globalconf.screens_info, c->phys_screen, for(tag = globalconf.screens[old_screen].tags; tag; tag = tag->next)
c->geometry.x, c->geometry.y); untag_client(c, tag);
/* nothing to do */ c->screen = new_screen;
if(old_screen == new_screen)
return;
/* tag client with new screen tags */
tag_client_with_current_selected(c);
/* resize the windows if it's floating */
if(doresize && old_screen != c->screen)
{
area_t new_geometry, new_f_geometry;
new_f_geometry = c->f_geometry; new_f_geometry = c->f_geometry;
to = screen_area_get(c->screen, NULL, NULL);
from = screen_area_get(old_screen, NULL, NULL); from = screen_area_get(old_screen, NULL, NULL);
to = screen_area_get(new_screen, NULL, NULL);
/* compute new coords in new screen */ /* compute new coords in new screen */
new_f_geometry.x = (c->f_geometry.x - from.x) + to.x; new_f_geometry.x = (c->f_geometry.x - from.x) + to.x;
@ -194,7 +202,12 @@ screen_client_moveto(client_t *c, int new_screen)
client_resize(c, new_f_geometry, false); client_resize(c, new_f_geometry, false);
/* otherwise just register them */ /* otherwise just register them */
else else
{
c->f_geometry = new_f_geometry; c->f_geometry = new_f_geometry;
globalconf.screens[old_screen].need_arrange = true;
globalconf.screens[c->screen].need_arrange = true;
}
}
} }
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -27,7 +27,7 @@
area_t screen_area_get(int, statusbar_t *, padding_t *); area_t screen_area_get(int, statusbar_t *, padding_t *);
area_t display_area_get(int, statusbar_t *, padding_t *); area_t display_area_get(int, statusbar_t *, padding_t *);
int screen_virttophys(int); int screen_virttophys(int);
void screen_client_moveto(client_t *, int); void screen_client_moveto(client_t *, int, bool);
#endif #endif
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -24,6 +24,7 @@
#include "statusbar.h" #include "statusbar.h"
#include "screen.h" #include "screen.h"
#include "tag.h"
#include "widget.h" #include "widget.h"
#include "window.h" #include "window.h"
@ -79,8 +80,7 @@ statusbar_position_update(statusbar_t *statusbar, position_t position)
xcb_screen_t *s = NULL; xcb_screen_t *s = NULL;
bool ignore = false; bool ignore = false;
if(globalconf.screens[statusbar->screen].workspace) globalconf.screens[statusbar->screen].need_arrange = true;
globalconf.screens[statusbar->screen].workspace->need_arrange = true;
simplewindow_delete(&statusbar->sw); simplewindow_delete(&statusbar->sw);
draw_context_delete(&statusbar->ctx); draw_context_delete(&statusbar->ctx);
@ -412,8 +412,7 @@ luaA_statusbar_remove(lua_State *L)
statusbar_position_update(*sb, Off); statusbar_position_update(*sb, Off);
statusbar_list_detach(&globalconf.screens[i].statusbar, *sb); statusbar_list_detach(&globalconf.screens[i].statusbar, *sb);
statusbar_unref(sb); statusbar_unref(sb);
if(globalconf.screens[s->screen].workspace) globalconf.screens[i].need_arrange = true;
globalconf.screens[s->screen].workspace->need_arrange = true;
return 0; return 0;
} }

View File

@ -50,8 +50,6 @@ enum
CurTopLeft, CurTopRight, CurBotLeft, CurBotRight, CurLast CurTopLeft, CurTopRight, CurBotLeft, CurBotRight, CurLast
}; };
typedef struct workspace_t workspace_t;
typedef void (layout_t)(workspace_t *);
typedef struct button_t button_t; typedef struct button_t button_t;
typedef struct widget_t widget_t; typedef struct widget_t widget_t;
typedef struct widget_node_t widget_node_t; typedef struct widget_node_t widget_node_t;
@ -60,7 +58,8 @@ typedef struct client_t client_t;
typedef struct titlebar_t titlebar_t; typedef struct titlebar_t titlebar_t;
typedef struct keybinding_t keybinding_t; typedef struct keybinding_t keybinding_t;
typedef struct client_node_t client_node_t; typedef struct client_node_t client_node_t;
typedef struct workspace_client_node_t workspace_client_node_t; typedef struct _tag_t tag_t;
typedef struct tag_client_node_t tag_client_node_t;
typedef area_t (FloatingPlacement)(client_t *); typedef area_t (FloatingPlacement)(client_t *);
typedef struct awesome_t awesome_t; typedef struct awesome_t awesome_t;
@ -280,6 +279,8 @@ struct client_t
bool skiptb; bool skiptb;
/** Window of the client */ /** Window of the client */
xcb_window_t win; xcb_window_t win;
/** Client logical screen */
int screen;
/** Client physical screen */ /** Client physical screen */
int phys_screen; int phys_screen;
/** Layer in the stacking order */ /** Layer in the stacking order */
@ -300,14 +301,18 @@ struct client_node_t
client_node_t *prev, *next; client_node_t *prev, *next;
}; };
/** Workspace type */ /** Tag type */
struct workspace_t struct _tag_t
{ {
/** Ref count */ /** Ref count */
int refcount; int refcount;
/** Tag name */ /** Tag name */
char *name; char *name;
/** Current workspace layout */ /** Screen */
int screen;
/** true if selected */
bool selected;
/** Current tag layout */
layout_t *layout; layout_t *layout;
/** Master width factor */ /** Master width factor */
double mwfact; double mwfact;
@ -315,19 +320,17 @@ struct workspace_t
int nmaster; int nmaster;
/** Number of columns in tile layout */ /** Number of columns in tile layout */
int ncol; int ncol;
/** True if we need to arrange() */ /** Next and previous tags */
bool need_arrange; tag_t *prev, *next;
/** Next and previous workspaces */
workspace_t *prev, *next;
}; };
/** Tag client link type */ /** Tag client link type */
struct workspace_client_node_t struct tag_client_node_t
{ {
workspace_t *workspace; tag_t *tag;
client_t *client; client_t *client;
/** Next and previous workspace_client_nodes */ /** Next and previous tag_client_nodes */
workspace_client_node_t *prev, *next; tag_client_node_t *prev, *next;
}; };
/** Padding type */ /** Padding type */
@ -343,15 +346,16 @@ typedef struct
int right; int right;
} padding_t; } padding_t;
/** An awesome screen. */
typedef struct typedef struct
{ {
/** true if we need to arrange() */
bool need_arrange;
/** Tag list */
tag_t *tags;
/** Status bar */ /** Status bar */
statusbar_t *statusbar; statusbar_t *statusbar;
/** Padding */ /** Padding */
padding_t padding; padding_t padding;
/** Visible workspace */
workspace_t *workspace;
} screen_t; } screen_t;
/** Main configuration structure */ /** Main configuration structure */
@ -400,8 +404,8 @@ struct awesome_t
client_node_t *focus; client_node_t *focus;
/** Stack client history */ /** Stack client history */
client_node_t *stack; client_node_t *stack;
/** Link between workspaces and clients */ /** Link between tags and clients */
workspace_client_node_t *wclink; tag_client_node_t *tclink;
/** Command line passed to awesome */ /** Command line passed to awesome */
char *argv; char *argv;
/** Last XMotionEvent coords */ /** Last XMotionEvent coords */
@ -440,8 +444,6 @@ struct awesome_t
} hooks; } hooks;
/** The timeout after which we need to stop select() */ /** The timeout after which we need to stop select() */
struct timeval timer; struct timeval timer;
/** Workspace list */
workspace_t *workspaces;
}; };
#endif #endif

564
tag.c Normal file
View File

@ -0,0 +1,564 @@
/*
* tag.c - tag management
*
* Copyright © 2007-2008 Julien Danjou <julien@danjou.info>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdio.h>
#include <X11/Xutil.h>
#include "screen.h"
#include "tag.h"
#include "client.h"
#include "ewmh.h"
#include "widget.h"
#include "layouts/magnifier.h"
#include "layouts/tile.h"
#include "layouts/max.h"
#include "layouts/floating.h"
#include "layouts/fibonacci.h"
#include "layoutgen.h"
extern awesome_t globalconf;
/** View or unview a tag.
* \param tag the tag
* \param view set visible or not
*/
static void
tag_view(tag_t *tag, bool view)
{
tag->selected = view;
ewmh_update_net_current_desktop(screen_virttophys(tag->screen));
widget_invalidate_cache(tag->screen, WIDGET_CACHE_TAGS);
globalconf.screens[tag->screen].need_arrange = true;
}
/** Create a new tag. Parameteres values are checked.
* \param name tag name
* \param layout layout to use
* \param mwfact master width factor
* \param nmaster number of master windows
* \param ncol number of columns for slaves windows
* \return a new tag with all these parameters
*/
tag_t *
tag_new(const char *name, layout_t *layout, double mwfact, int nmaster, int ncol)
{
tag_t *tag;
tag = p_new(tag_t, 1);
tag->name = a_strdup(name);
tag->layout = layout;
tag->mwfact = mwfact;
if(tag->mwfact <= 0 || tag->mwfact >= 1)
tag->mwfact = 0.5;
if((tag->nmaster = nmaster) < 0)
tag->nmaster = 1;
if((tag->ncol = ncol) < 1)
tag->ncol = 1;
return tag;
}
/** Append a tag to a screen.
* \param tag the tag to append
* \param screen the screen id
*/
void
tag_append_to_screen(tag_t *tag, int screen)
{
int phys_screen = screen_virttophys(screen);
tag->screen = screen;
tag_list_append(&globalconf.screens[screen].tags, tag);
tag_ref(&tag);
ewmh_update_net_numbers_of_desktop(phys_screen);
ewmh_update_net_desktop_names(phys_screen);
widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
}
/** Tag a client with specified tag.
* \param c the client to tag
* \param t the tag to tag the client with
*/
void
tag_client(client_t *c, tag_t *t)
{
tag_client_node_t *tc;
/* don't tag twice */
if(is_client_tagged(c, t))
return;
tc = p_new(tag_client_node_t, 1);
tc->client = c;
tc->tag = t;
tag_client_node_list_push(&globalconf.tclink, tc);
client_saveprops(c);
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
globalconf.screens[c->screen].need_arrange = true;
}
/** Untag a client with specified tag.
* \param c the client to tag
* \param t the tag to tag the client with
*/
void
untag_client(client_t *c, tag_t *t)
{
tag_client_node_t *tc;
for(tc = globalconf.tclink; tc; tc = tc->next)
if(tc->client == c && tc->tag == t)
{
tag_client_node_list_detach(&globalconf.tclink, tc);
p_delete(&tc);
client_saveprops(c);
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
globalconf.screens[c->screen].need_arrange = True;
break;
}
}
/** Check if a client is tagged with the specified tag.
* \param c the client
* \param t the tag
* \return true if the client is tagged with the tag, false otherwise.
*/
bool
is_client_tagged(client_t *c, tag_t *t)
{
tag_client_node_t *tc;
if(!c)
return false;
for(tc = globalconf.tclink; tc; tc = tc->next)
if(tc->client == c && tc->tag == t)
return true;
return false;
}
/** Tag the client with the currently selected (visible) tags.
* \param c the client
*/
void
tag_client_with_current_selected(client_t *c)
{
tag_t *tag;
screen_t vscreen = globalconf.screens[c->screen];
for(tag = vscreen.tags; tag; tag = tag->next)
if(tag->selected)
tag_client(c, tag);
else
untag_client(c, tag);
}
/** Get the current tags for the specified screen.
* Returned pointer must be p_delete'd after.
* \param screen screen id
* \return a double pointer of tag list finished with a NULL element
*/
tag_t **
tags_get_current(int screen)
{
tag_t *tag, **tags = NULL;
int n = 1;
tags = p_new(tag_t *, n);
for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
if(tag->selected)
{
p_realloc(&tags, ++n);
tags[n - 2] = tag;
}
/* finish with null */
tags[n - 1] = NULL;
return tags;
}
/** Set a tag to be the only one viewed.
* \param target the tag to see
*/
static void
tag_view_only(tag_t *target)
{
tag_t *tag;
if(!target) return;
for(tag = globalconf.screens[target->screen].tags; tag; tag = tag->next)
tag_view(tag, tag == target);
}
/** View only a tag, selected by its index.
* \param screen screen id
* \param dindex the index
*/
void
tag_view_only_byindex(int screen, int dindex)
{
tag_t *tag;
if(dindex < 0)
return;
for(tag = globalconf.screens[screen].tags; tag && dindex > 0;
tag = tag->next, dindex--);
tag_view_only(tag);
}
/** Check for tag equality.
* \param Another tag.
* \return True if tags are equals.
*/
static int
luaA_tag_eq(lua_State *L)
{
tag_t **t1 = luaA_checkudata(L, 1, "tag");
tag_t **t2 = luaA_checkudata(L, 2, "tag");
lua_pushboolean(L, (*t1 == *t2));
return 1;
}
/** Convert a tag to a printable string.
* \return A string.
*/
static int
luaA_tag_tostring(lua_State *L)
{
tag_t **p = luaA_checkudata(L, 1, "tag");
lua_pushfstring(L, "[tag udata(%p) name(%s)]", *p, (*p)->name);
return 1;
}
/** Add a tag to a screen.
* \param A screen number.
*/
static int
luaA_tag_add(lua_State *L)
{
tag_t *t, **tag = luaA_checkudata(L, 1, "tag");
int i, screen = luaL_checknumber(L, 2) - 1;
luaA_checkscreen(screen);
for(i = 0; i < globalconf.screens_info->nscreen; i++)
for(t = globalconf.screens[i].tags; t; t = t->next)
if(*tag == t)
luaL_error(L, "tag already on screen %d", i + 1);
(*tag)->screen = screen;
tag_append_to_screen(*tag, screen);
return 0;
}
/** Get all tags from a screen.
* \param A screen number.
* \return A table with all tags from the screen specified.
*/
static int
luaA_tag_get(lua_State *L)
{
int screen = luaL_checknumber(L, 1) - 1;
tag_t *tag;
int i = 1;
luaA_checkscreen(screen);
lua_newtable(L);
for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
{
luaA_tag_userdata_new(tag);
lua_rawseti(L, -2, i++);
}
return 1;
}
/** Create a new tag.
* \param A table with at least a name attribute.
* Optionnal attributes are: mwfact, ncol, nmaster and layout.
* \return A new tag object.
*/
static int
luaA_tag_new(lua_State *L)
{
tag_t *tag;
int ncol, nmaster;
const char *name, *lay;
double mwfact;
layout_t *layout;
luaA_checktable(L, 1);
name = luaA_name_init(L);
mwfact = luaA_getopt_number(L, 1, "mwfact", 0.5);
ncol = luaA_getopt_number(L, 1, "ncol", 1);
nmaster = luaA_getopt_number(L, 1, "nmaster", 1);
lay = luaA_getopt_string(L, 1, "layout", "tile");
layout = name_func_lookup(lay, LayoutList);
tag = tag_new(name,
layout,
mwfact, nmaster, ncol);
return luaA_tag_userdata_new(tag);
}
/** Add or remove a tag from the current view.
* \param A boolean value, true to view tag, false otherwise.
*/
static int
luaA_tag_view(lua_State *L)
{
tag_t **tag = luaA_checkudata(L, 1, "tag");
bool view = luaA_checkboolean(L, 2);
tag_view(*tag, view);
return 0;
}
/** Get the tag selection attribute.
* \return True if the tag is viewed, false otherwise.
*/
static int
luaA_tag_isselected(lua_State *L)
{
tag_t **tag = luaA_checkudata(L, 1, "tag");
lua_pushboolean(L, (*tag)->selected);
return 1;
}
/** Set the tag master width factor. This value is used in various layouts to
* determine the size of the master window.
* \param The master width ratio value, between 0 and 1.
*/
static int
luaA_tag_mwfact_set(lua_State *L)
{
tag_t **tag = luaA_checkudata(L, 1, "tag");
double mwfact = luaL_checknumber(L, 2);
if(mwfact < 1 && mwfact > 0)
{
(*tag)->mwfact = mwfact;
globalconf.screens[(*tag)->screen].need_arrange = true;
}
else
luaL_error(L, "bad value, must be between 0 and 1");
return 0;
}
/** Get the tag master width factor.
* \return The master width ratio value.
*/
static int
luaA_tag_mwfact_get(lua_State *L)
{
tag_t **tag = luaA_checkudata(L, 1, "tag");
lua_pushnumber(L, (*tag)->mwfact);
return 1;
}
/** Set the number of columns. This is used in various layouts to set the number
* of columns used to display non-master windows.
* \param The number of columns, at least 1.
*/
static int
luaA_tag_ncol_set(lua_State *L)
{
tag_t **tag = luaA_checkudata(L, 1, "tag");
int ncol = luaL_checknumber(L, 2);
if(ncol >= 1)
{
(*tag)->ncol = ncol;
globalconf.screens[(*tag)->screen].need_arrange = true;
}
else
luaL_error(L, "bad value, must be greater than 1");
return 0;
}
/** Get the number of columns used to display non-master windows on this tag.
* \return The number of column.
*/
static int
luaA_tag_ncol_get(lua_State *L)
{
tag_t **tag = luaA_checkudata(L, 1, "tag");
lua_pushnumber(L, (*tag)->ncol);
return 1;
}
/** Set the number of master windows. This is used in various layouts to
* determine how many windows are in the master area.
* \param The number of master windows.
*/
static int
luaA_tag_nmaster_set(lua_State *L)
{
tag_t **tag = luaA_checkudata(L, 1, "tag");
int nmaster = luaL_checknumber(L, 2);
if(nmaster >= 0)
{
(*tag)->nmaster = nmaster;
globalconf.screens[(*tag)->screen].need_arrange = true;
}
else
luaL_error(L, "bad value, must be greater than 0");
return 0;
}
/** Get the number of master windows of the tag.
* \return The number of master windows.
*/
static int
luaA_tag_nmaster_get(lua_State *L)
{
tag_t **tag = luaA_checkudata(L, 1, "tag");
lua_pushnumber(L, (*tag)->nmaster);
return 1;
}
/** Get the tag name.
* \return The tag name.
*/
static int
luaA_tag_name_get(lua_State *L)
{
tag_t **tag = luaA_checkudata(L, 1, "tag");
lua_pushstring(L, (*tag)->name);
return 1;
}
/** Set the tag name.
* \param A string with the new tag name.
*/
static int
luaA_tag_name_set(lua_State *L)
{
tag_t **tag = luaA_checkudata(L, 1, "tag");
const char *name = luaL_checkstring(L, 2);
p_delete(&(*tag)->name);
(*tag)->name = a_strdup(name);
return 0;
}
/** Handle tag garbage collection.
*/
static int
luaA_tag_gc(lua_State *L)
{
tag_t **tag = luaA_checkudata(L, 1, "tag");
tag_unref(tag);
*tag = NULL;
return 0;
}
/** Get the layout of the tag.
* \return The layout name.
*/
static int
luaA_tag_layout_get(lua_State *L)
{
tag_t **tag = luaA_checkudata(L, 1, "tag");
const char *name = a_strdup(name_func_rlookup((*tag)->layout, LayoutList));
lua_pushstring(L, name);
return 1;
}
/** Set the layout of the tag.
* \param A layout name.
*/
static int
luaA_tag_layout_set(lua_State *L)
{
tag_t **tag = luaA_checkudata(L, 1, "tag");
const char *name = luaL_checkstring(L, 2);
layout_t *l = name_func_lookup(name, LayoutList);
if(l)
{
(*tag)->layout = l;
globalconf.screens[(*tag)->screen].need_arrange = true;
}
else
luaL_error(L, "unknown layout: %s", name);
return 0;
}
/** Create a new userdata from a tag.
* \param t The tag.
* \return The luaA_settype returnn value.
*/
int
luaA_tag_userdata_new(tag_t *t)
{
tag_t **lt = lua_newuserdata(globalconf.L, sizeof(tag_t *));
*lt = t;
tag_ref(lt);
return luaA_settype(globalconf.L, "tag");
}
const struct luaL_reg awesome_tag_methods[] =
{
{ "new", luaA_tag_new },
{ "get", luaA_tag_get},
{ NULL, NULL }
};
const struct luaL_reg awesome_tag_meta[] =
{
{ "add", luaA_tag_add },
{ "view", luaA_tag_view },
{ "isselected", luaA_tag_isselected },
{ "mwfact_set", luaA_tag_mwfact_set },
{ "mwfact_get", luaA_tag_mwfact_get },
{ "ncol_set", luaA_tag_ncol_set },
{ "ncol_get", luaA_tag_ncol_get },
{ "nmaster_set", luaA_tag_nmaster_set },
{ "nmaster_get", luaA_tag_nmaster_get },
{ "name_get", luaA_tag_name_get },
{ "name_set", luaA_tag_name_set },
{ "layout_get", luaA_tag_layout_get },
{ "layout_set", luaA_tag_layout_set },
{ "__eq", luaA_tag_eq },
{ "__gc", luaA_tag_gc },
{ "__tostring", luaA_tag_tostring },
{ NULL, NULL },
};
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -1,5 +1,5 @@
/* /*
* workspace.h - workspace management header * tag.h - tag management header
* *
* Copyright © 2007-2008 Julien Danjou <julien@danjou.info> * Copyright © 2007-2008 Julien Danjou <julien@danjou.info>
* *
@ -19,8 +19,8 @@
* *
*/ */
#ifndef AWESOME_WORKSPACE_H #ifndef AWESOME_TAG_H
#define AWESOME_WORKSPACE_H #define AWESOME_TAG_H
#include "structs.h" #include "structs.h"
#include "common/refcount.h" #include "common/refcount.h"
@ -29,26 +29,28 @@
#define IS_TILED(client, screen) (client && !client->isfloating && !client->ismax && client_isvisible(client, screen)) #define IS_TILED(client, screen) (client && !client->isfloating && !client->ismax && client_isvisible(client, screen))
/* Contructor, destructor and referencors */ /* Contructor, destructor and referencors */
workspace_t * workspace_new(const char *, layout_t *, double, int, int); tag_t * tag_new(const char *, layout_t *, double, int, int);
static inline void static inline void
workspace_delete(workspace_t **workspace) tag_delete(tag_t **tag)
{ {
p_delete(&(*workspace)->name); p_delete(&(*tag)->name);
p_delete(workspace); p_delete(tag);
} }
void workspace_client_set(client_t *, workspace_t *); tag_t ** tags_get_current(int);
workspace_t * workspace_client_get(client_t *); void tag_client(client_t *, tag_t *);
void workspace_client_remove(client_t *); void untag_client(client_t *, tag_t *);
int workspace_screen_get(workspace_t *); bool is_client_tagged(client_t *, tag_t *);
void tag_client_with_current_selected(client_t *);
void tag_view_only_byindex(int, int);
void tag_append_to_screen(tag_t *, int);
int luaA_tag_userdata_new(tag_t *);
int luaA_workspace_userdata_new(workspace_t *); DO_RCNT(tag_t, tag, tag_delete)
DO_SLIST(tag_t, tag, tag_delete)
DO_RCNT(workspace_t, workspace, workspace_delete) DO_SLIST(tag_client_node_t, tag_client_node, p_delete)
DO_SLIST(workspace_t, workspace, workspace_delete)
DO_SLIST(workspace_client_node_t, workspace_client_node, p_delete)
#endif #endif
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -28,7 +28,6 @@
#include "client.h" #include "client.h"
#include "screen.h" #include "screen.h"
#include "widget.h" #include "widget.h"
#include "workspace.h"
#include "layouts/floating.h" #include "layouts/floating.h"
extern awesome_t globalconf; extern awesome_t globalconf;
@ -111,7 +110,7 @@ titlebar_draw(client_t *c)
} }
widget_render(c->titlebar->widgets, ctx, c->titlebar->sw->gc, c->titlebar->sw->pixmap, widget_render(c->titlebar->widgets, ctx, c->titlebar->sw->gc, c->titlebar->sw->pixmap,
workspace_screen_get(workspace_client_get(c)), c->titlebar->position, c->screen, c->titlebar->position,
c->titlebar->sw->geometry.x, c->titlebar->sw->geometry.y, c->titlebar); c->titlebar->sw->geometry.x, c->titlebar->sw->geometry.y, c->titlebar);
switch(c->titlebar->position) switch(c->titlebar->position)

View File

@ -248,16 +248,15 @@ widget_common_new(widget_t *widget)
/** Invalidate widgets which should be refresh upon /** Invalidate widgets which should be refresh upon
* external modifications. widget_t who watch flags will * external modifications. widget_t who watch flags will
* be set to be refreshed. * be set to be refreshed.
* \param screen Virtual screen number.
* \param flags Cache flags to invalidate. * \param flags Cache flags to invalidate.
*/ */
void void
widget_invalidate_cache(int flags) widget_invalidate_cache(int screen, int flags)
{ {
statusbar_t *statusbar; statusbar_t *statusbar;
widget_node_t *widget; widget_node_t *widget;
int screen;
for(screen = 0; screen < globalconf.screens_info->nscreen; screen++)
for(statusbar = globalconf.screens[screen].statusbar; for(statusbar = globalconf.screens[screen].statusbar;
statusbar; statusbar;
statusbar = statusbar->next) statusbar = statusbar->next)

View File

@ -27,12 +27,12 @@
#define WIDGET_CACHE_CLIENTS 1<<0 #define WIDGET_CACHE_CLIENTS 1<<0
#define WIDGET_CACHE_LAYOUTS 1<<1 #define WIDGET_CACHE_LAYOUTS 1<<1
#define WIDGET_CACHE_WORKSPACES 1<<2 #define WIDGET_CACHE_TAGS 1<<2
#define WIDGET_CACHE_ALL (WIDGET_CACHE_CLIENTS | WIDGET_CACHE_LAYOUTS | WIDGET_CACHE_WORKSPACES) #define WIDGET_CACHE_ALL (WIDGET_CACHE_CLIENTS | WIDGET_CACHE_LAYOUTS | WIDGET_CACHE_TAGS)
typedef widget_t *(widget_constructor_t)(alignment_t); typedef widget_t *(widget_constructor_t)(alignment_t);
void widget_invalidate_cache(int); void widget_invalidate_cache(int, int);
int widget_calculate_offset(int, int, int, int); int widget_calculate_offset(int, int, int, int);
void widget_common_new(widget_t *); void widget_common_new(widget_t *);
widget_t * widget_getbyname(const char *); widget_t * widget_getbyname(const char *);
@ -41,7 +41,7 @@ void widget_render(widget_node_t *, draw_context_t *, xcb_gcontext_t, xcb_drawab
int luaA_widget_userdata_new(widget_t *); int luaA_widget_userdata_new(widget_t *);
widget_constructor_t workspacelist_new; widget_constructor_t taglist_new;
widget_constructor_t textbox_new; widget_constructor_t textbox_new;
widget_constructor_t iconbox_new; widget_constructor_t iconbox_new;
widget_constructor_t progressbar_new; widget_constructor_t progressbar_new;

View File

@ -1,7 +1,6 @@
/* /*
* workspacelist.c - workspace list widget * taglist.c - tag list widget
* *
* Copyright © 2008 Julien Danjou <julien@danjou.info>
* Copyright © 2007 Aldo Cortesi <aldo@nullcube.com> * Copyright © 2007 Aldo Cortesi <aldo@nullcube.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -22,7 +21,7 @@
#include "client.h" #include "client.h"
#include "widget.h" #include "widget.h"
#include "workspace.h" #include "tag.h"
#include "lua.h" #include "lua.h"
#include "event.h" #include "event.h"
#include "common/markup.h" #include "common/markup.h"
@ -30,26 +29,26 @@
extern awesome_t globalconf; extern awesome_t globalconf;
typedef struct workspacelist_drawn_area_t workspacelist_drawn_area_t; typedef struct taglist_drawn_area_t taglist_drawn_area_t;
struct workspacelist_drawn_area_t struct taglist_drawn_area_t
{ {
void *object; void *object;
area_t *area; area_t *area;
workspacelist_drawn_area_t *next, *prev; taglist_drawn_area_t *next, *prev;
}; };
DO_SLIST(workspacelist_drawn_area_t, workspacelist_drawn_area, p_delete); DO_SLIST(taglist_drawn_area_t, taglist_drawn_area, p_delete);
typedef struct typedef struct
{ {
char *text_normal, *text_focus, *text_urgent; char *text_normal, *text_focus, *text_urgent;
bool show_empty; bool show_empty;
workspacelist_drawn_area_t *drawn_area; taglist_drawn_area_t *drawn_area;
} workspacelist_data_t; } taglist_data_t;
static char * static char *
workspace_markup_parse(workspace_t *t, const char *str, ssize_t len) tag_markup_parse(tag_t *t, const char *str, ssize_t len)
{ {
const char *elements[] = { "title", NULL }; const char *elements[] = { "title", NULL };
char *title_esc = g_markup_escape_text(t->name, -1); char *title_esc = g_markup_escape_text(t->name, -1);
@ -73,88 +72,89 @@ workspace_markup_parse(workspace_t *t, const char *str, ssize_t len)
return ret; return ret;
} }
/** Check if at least one client is on the workspace. /** Check if at least one client is tagged with tag number t and is on screen
* \param ws The workspace. * screen
* \return True or false. * \param t tag
* \return true or false
*/ */
static bool static bool
workspace_isoccupied(workspace_t *ws) tag_isoccupied(tag_t *t)
{ {
client_t *c; client_t *c;
for(c = globalconf.clients; c; c = c->next) for(c = globalconf.clients; c; c = c->next)
if(workspace_client_get(c) == ws) if(is_client_tagged(c, t) && !c->skip)
return true; return true;
return false; return false;
} }
static bool static bool
workspace_isurgent(workspace_t *ws) tag_isurgent(tag_t *t)
{ {
client_t *c; client_t *c;
for(c = globalconf.clients; c; c = c->next) for(c = globalconf.clients; c; c = c->next)
if(c->isurgent && workspace_client_get(c) == ws) if(is_client_tagged(c, t) && c->isurgent)
return true; return true;
return false; return false;
} }
static char * static char *
workspacelist_text_get(workspace_t *ws, screen_t *screen, workspacelist_data_t *data) taglist_text_get(tag_t *tag, taglist_data_t *data)
{ {
if(screen->workspace == ws) if(tag->selected)
return data->text_focus; return data->text_focus;
else if(tag_isurgent(tag))
if(workspace_isurgent(ws))
return data->text_urgent; return data->text_urgent;
return data->text_normal; return data->text_normal;
} }
static int static int
workspacelist_draw(draw_context_t *ctx, int screen, taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w,
widget_node_t *w,
int offset, int offset,
int used __attribute__ ((unused)), int used __attribute__ ((unused)),
void *object) void *object)
{ {
workspace_t *ws; tag_t *tag;
workspacelist_data_t *data = w->widget->data; taglist_data_t *data = w->widget->data;
client_t *sel = globalconf.focus->client;
screen_t *vscreen = &globalconf.screens[screen];
int i = 0, prev_width = 0; int i = 0, prev_width = 0;
area_t *area, rectangle = { 0, 0, 0, 0, NULL, NULL }; area_t *area, rectangle = { 0, 0, 0, 0, NULL, NULL };
char **text = NULL; char **text = NULL;
workspacelist_drawn_area_t *tda; taglist_drawn_area_t *tda;
w->area.width = w->area.y = 0; w->area.width = w->area.y = 0;
/* Lookup for our workspacelist_drawn_area. /* Lookup for our taglist_drawn_area.
* This will be used to store area where we draw ws list for each object. */ * This will be used to store area where we draw tag list for each object. */
for(tda = data->drawn_area; tda && tda->object != object; tda = tda->next); for(tda = data->drawn_area; tda && tda->object != object; tda = tda->next);
/* Oh, we did not find a drawn area for our object. First time? */ /* Oh, we did not find a drawn area for our object. First time? */
if(!tda) if(!tda)
{ {
/** \todo delete this when the widget is removed from the object */ /** \todo delete this when the widget is removed from the object */
tda = p_new(workspacelist_drawn_area_t, 1); tda = p_new(taglist_drawn_area_t, 1);
tda->object = object; tda->object = object;
workspacelist_drawn_area_list_push(&data->drawn_area, tda); taglist_drawn_area_list_push(&data->drawn_area, tda);
} }
area_list_wipe(&tda->area); area_list_wipe(&tda->area);
/* First compute text and widget width */ /* First compute text and widget width */
for(ws = globalconf.workspaces; ws; ws = ws->next, i++) for(tag = vscreen->tags; tag; tag = tag->next, i++)
{ {
p_realloc(&text, i + 1); p_realloc(&text, i + 1);
area = p_new(area_t, 1); area = p_new(area_t, 1);
text[i] = workspacelist_text_get(ws, &globalconf.screens[screen], data); text[i] = taglist_text_get(tag, data);
text[i] = workspace_markup_parse(ws, text[i], a_strlen(text[i])); text[i] = tag_markup_parse(tag, text[i], a_strlen(text[i]));
*area = draw_text_extents(ctx->connection, ctx->phys_screen, *area = draw_text_extents(ctx->connection, ctx->phys_screen,
globalconf.font, text[i]); globalconf.font, text[i]);
if (data->show_empty || workspace_isoccupied(ws)) if (data->show_empty || tag->selected || tag_isoccupied(tag))
w->area.width += area->width; w->area.width += area->width;
area_list_append(&tda->area, area); area_list_append(&tda->area, area);
@ -164,11 +164,11 @@ workspacelist_draw(draw_context_t *ctx, int screen,
w->area.x = widget_calculate_offset(ctx->width, w->area.width, w->area.x = widget_calculate_offset(ctx->width, w->area.width,
offset, w->widget->align); offset, w->widget->align);
for(area = tda->area, ws = globalconf.workspaces, i = 0; for(area = tda->area, tag = vscreen->tags, i = 0;
ws && area; tag && area;
ws = ws->next, area = area->next, i++) tag = tag->next, area = area->next, i++)
{ {
if (!data->show_empty && !workspace_isoccupied(ws)) if (!data->show_empty && !tag->selected && !tag_isoccupied(tag))
continue; continue;
area->x = w->area.x + prev_width; area->x = w->area.x + prev_width;
@ -176,12 +176,13 @@ workspacelist_draw(draw_context_t *ctx, int screen,
draw_text(ctx, globalconf.font, *area, text[i]); draw_text(ctx, globalconf.font, *area, text[i]);
p_delete(&text[i]); p_delete(&text[i]);
if(workspace_isoccupied(ws)) if(tag_isoccupied(tag))
{ {
rectangle.width = rectangle.height = (globalconf.font->height + 2) / 3; rectangle.width = rectangle.height = (globalconf.font->height + 2) / 3;
rectangle.x = area->x; rectangle.x = area->x;
rectangle.y = area->y; rectangle.y = area->y;
draw_rectangle(ctx, rectangle, 1.0, false, ctx->fg); draw_rectangle(ctx, rectangle, 1.0,
sel && is_client_tagged(sel, tag), ctx->fg);
} }
} }
@ -199,17 +200,18 @@ workspacelist_draw(draw_context_t *ctx, int screen,
* \param type The type object. * \param type The type object.
*/ */
static void static void
workspacelist_button_press(widget_node_t *w, taglist_button_press(widget_node_t *w,
xcb_button_press_event_t *ev, xcb_button_press_event_t *ev,
int screen __attribute__ ((unused)), int screen,
void *object, void *object,
awesome_type_t type) awesome_type_t type)
{ {
screen_t *vscreen = &globalconf.screens[screen];
button_t *b; button_t *b;
workspacelist_data_t *data = w->widget->data; taglist_data_t *data = w->widget->data;
workspacelist_drawn_area_t *tda; taglist_drawn_area_t *tda;
area_t *area; area_t *area;
workspace_t *ws; tag_t *tag;
/* Find the good drawn area list */ /* Find the good drawn area list */
for(tda = data->drawn_area; tda && tda->object != object; tda = tda->next); for(tda = data->drawn_area; tda && tda->object != object; tda = tda->next);
@ -217,22 +219,22 @@ workspacelist_button_press(widget_node_t *w,
for(b = w->widget->buttons; b; b = b->next) for(b = w->widget->buttons; b; b = b->next)
if(ev->detail == b->button && CLEANMASK(ev->state) == b->mod && b->fct) if(ev->detail == b->button && CLEANMASK(ev->state) == b->mod && b->fct)
for(ws = globalconf.workspaces; ws && area; ws = ws->next, area = area->next) for(tag = vscreen->tags; tag && area; tag = tag->next, area = area->next)
if(ev->event_x >= AREA_LEFT(*area) if(ev->event_x >= AREA_LEFT(*area)
&& ev->event_x < AREA_RIGHT(*area) && ev->event_x < AREA_RIGHT(*area)
&& (data->show_empty || workspace_isoccupied(ws)) ) && (data->show_empty || tag->selected || tag_isoccupied(tag)) )
{ {
luaA_pushpointer(object, type); luaA_pushpointer(object, type);
luaA_workspace_userdata_new(ws); luaA_tag_userdata_new(tag);
luaA_dofunction(globalconf.L, b->fct, 2); luaA_dofunction(globalconf.L, b->fct, 2);
return; return;
} }
} }
static widget_tell_status_t static widget_tell_status_t
workspacelist_tell(widget_t *widget, const char *property, const char *new_value) taglist_tell(widget_t *widget, const char *property, const char *new_value)
{ {
workspacelist_data_t *d = widget->data; taglist_data_t *d = widget->data;
if(!a_strcmp(property, "text_normal")) if(!a_strcmp(property, "text_normal"))
{ {
@ -258,26 +260,26 @@ workspacelist_tell(widget_t *widget, const char *property, const char *new_value
} }
widget_t * widget_t *
workspacelist_new(alignment_t align) taglist_new(alignment_t align)
{ {
widget_t *w; widget_t *w;
workspacelist_data_t *d; taglist_data_t *d;
w = p_new(widget_t, 1); w = p_new(widget_t, 1);
widget_common_new(w); widget_common_new(w);
w->align = align; w->align = align;
w->draw = workspacelist_draw; w->draw = taglist_draw;
w->button_press = workspacelist_button_press; w->button_press = taglist_button_press;
w->tell = workspacelist_tell; w->tell = taglist_tell;
w->data = d = p_new(workspacelist_data_t, 1); w->data = d = p_new(taglist_data_t, 1);
d->text_normal = a_strdup(" <text align=\"center\"/><title/> "); d->text_normal = a_strdup(" <text align=\"center\"/><title/> ");
d->text_focus = a_strdup(" <text align=\"center\"/><title/> "); d->text_focus = a_strdup(" <text align=\"center\"/><title/> ");
d->text_urgent = a_strdup(" <text align=\"center\"/><title/> "); d->text_urgent = a_strdup(" <text align=\"center\"/><title/> ");
d->show_empty = true; d->show_empty = true;
/* Set cache property */ /* Set cache property */
w->cache_flags = WIDGET_CACHE_WORKSPACES | WIDGET_CACHE_CLIENTS; w->cache_flags = WIDGET_CACHE_TAGS | WIDGET_CACHE_CLIENTS;
return w; return w;
} }

View File

@ -25,6 +25,7 @@
#include "screen.h" #include "screen.h"
#include "event.h" #include "event.h"
#include "ewmh.h" #include "ewmh.h"
#include "tag.h"
#include "common/configopts.h" #include "common/configopts.h"
#include "common/markup.h" #include "common/markup.h"
@ -33,7 +34,7 @@ extern awesome_t globalconf;
typedef enum typedef enum
{ {
ShowFocus, ShowFocus,
ShowWorkspace, ShowTags,
ShowAll, ShowAll,
} showclient_t; } showclient_t;
@ -53,11 +54,11 @@ tasklist_isvisible(client_t *c, int screen, showclient_t show)
switch(show) switch(show)
{ {
case ShowAll: case ShowAll:
return true; return (c->screen == screen);
case ShowWorkspace: case ShowTags:
return client_isvisible(c, screen); return client_isvisible(c, screen);
case ShowFocus: case ShowFocus:
return (c == focus_client_getcurrent(globalconf.screens[screen].workspace)); return (c == focus_get_current_client(screen));
} }
return false; return false;
} }
@ -262,8 +263,8 @@ tasklist_tell(widget_t *widget, const char *property, const char *new_value)
d->show_icons = a_strtobool(new_value); d->show_icons = a_strtobool(new_value);
else if(!a_strcmp(property, "show")) else if(!a_strcmp(property, "show"))
{ {
if(!a_strcmp(new_value, "workspace")) if(!a_strcmp(new_value, "tags"))
d->show = ShowWorkspace; d->show = ShowTags;
else if(!a_strcmp(new_value, "focus")) else if(!a_strcmp(new_value, "focus"))
d->show = ShowFocus; d->show = ShowFocus;
else if(!a_strcmp(new_value, "all")) else if(!a_strcmp(new_value, "all"))
@ -295,7 +296,7 @@ tasklist_new(alignment_t align __attribute__ ((unused)))
d->text_focus = a_strdup(" <title/> "); d->text_focus = a_strdup(" <title/> ");
d->text_urgent = a_strdup(" <title/> "); d->text_urgent = a_strdup(" <title/> ");
d->show_icons = true; d->show_icons = true;
d->show = ShowWorkspace; d->show = ShowTags;
/* Set cache property */ /* Set cache property */
w->cache_flags = WIDGET_CACHE_CLIENTS; w->cache_flags = WIDGET_CACHE_CLIENTS;

View File

@ -1,515 +0,0 @@
/*
* workspace.c - workspace management
*
* Copyright © 2007-2008 Julien Danjou <julien@danjou.info>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "screen.h"
#include "workspace.h"
#include "client.h"
#include "ewmh.h"
#include "client.h"
#include "focus.h"
#include "widget.h"
#include "layouts/magnifier.h"
#include "layouts/tile.h"
#include "layouts/max.h"
#include "layouts/floating.h"
#include "layouts/fibonacci.h"
#include "layoutgen.h"
extern awesome_t globalconf;
/** View a workspace.
* \param workspace The workspace.
* \param screen The screen to view on.
*/
static void
workspace_view(workspace_t *workspace, int screen)
{
int s;
for(s = 0; s < globalconf.screens_info->nscreen; s++)
/* The workspace is already viewed on `s': switch */
if(globalconf.screens[s].workspace == workspace)
{
globalconf.screens[s].workspace = globalconf.screens[screen].workspace;
globalconf.screens[s].workspace->need_arrange = true;
}
ewmh_update_net_current_desktop(screen_virttophys(screen));
widget_invalidate_cache(WIDGET_CACHE_WORKSPACES);
globalconf.screens[screen].workspace = workspace;
workspace->need_arrange = true;
}
/** Get the display screen for a workspace.
* \param ws A workspace.
* \return A screen number.
*/
int
workspace_screen_get(workspace_t *ws)
{
int screen = 0;
for(; screen < globalconf.screens_info->nscreen; screen++)
if(globalconf.screens[screen].workspace == ws)
return screen;
return -1;
}
/** Create a new workspace. Parameteres values are checked.
* \param name workspace name
* \param layout layout to use
* \param mwfact master width factor
* \param nmaster number of master windows
* \param ncol number of columns for slaves windows
* \return a new workspace with all these parameters
*/
workspace_t *
workspace_new(const char *name, layout_t *layout, double mwfact, int nmaster, int ncol)
{
workspace_t *workspace;
workspace = p_new(workspace_t, 1);
workspace->name = a_strdup(name);
workspace->layout = layout;
workspace->mwfact = mwfact;
if(workspace->mwfact <= 0 || workspace->mwfact >= 1)
workspace->mwfact = 0.5;
if((workspace->nmaster = nmaster) < 0)
workspace->nmaster = 1;
if((workspace->ncol = ncol) < 1)
workspace->ncol = 1;
return workspace;
}
static workspace_client_node_t *
workspace_client_getnode(client_t *c)
{
workspace_client_node_t *wc = NULL;
for(wc = globalconf.wclink; wc && wc->client != c; wc = wc->next);
return wc;
}
workspace_t *
workspace_client_get(client_t *c)
{
workspace_client_node_t *wc = workspace_client_getnode(c);
if(wc && wc->client == c)
return wc->workspace;
return NULL;
}
/** Remove the client from its workspace.
* \param c The client
*/
void
workspace_client_remove(client_t *c)
{
workspace_client_node_t *wc = workspace_client_getnode(c);
if(wc && wc->client == c)
{
workspace_client_node_list_detach(&globalconf.wclink, wc);
client_saveprops(c);
widget_invalidate_cache(WIDGET_CACHE_CLIENTS);
wc->workspace->need_arrange = true;
p_delete(&wc);
}
}
/** Put a client in the specified workspace.
* \param c The client.
* \param t The workspace.
*/
void
workspace_client_set(client_t *c, workspace_t *w)
{
workspace_client_node_t *wc;
if(!(wc = workspace_client_getnode(c)))
{
wc = p_new(workspace_client_node_t, 1);
wc->client = c;
workspace_client_node_list_push(&globalconf.wclink, wc);
}
wc->workspace = w;
client_saveprops(c);
widget_invalidate_cache(WIDGET_CACHE_CLIENTS);
w->need_arrange = true;
}
/** Check for workspace equality.
* \param Another workspace.
* \return True if workspaces are equals.
*/
static int
luaA_workspace_eq(lua_State *L)
{
workspace_t **t1 = luaA_checkudata(L, 1, "workspace");
workspace_t **t2 = luaA_checkudata(L, 2, "workspace");
lua_pushboolean(L, (*t1 == *t2));
return 1;
}
/** Convert a workspace to a printable string.
* \return A string.
*/
static int
luaA_workspace_tostring(lua_State *L)
{
workspace_t **p = luaA_checkudata(L, 1, "workspace");
lua_pushfstring(L, "[workspace udata(%p) name(%s)]", *p, (*p)->name);
return 1;
}
/** Add a workspace.
*/
static int
luaA_workspace_add(lua_State *L)
{
workspace_t *t, **workspace = luaA_checkudata(L, 1, "workspace");
for(t = globalconf.workspaces; t; t = t->next)
if(*workspace == t)
luaL_error(L, "workspace already added");
workspace_list_append(&globalconf.workspaces, *workspace);
workspace_ref(workspace);
/* \todo do it for all screens */
ewmh_update_net_numbers_of_desktop(globalconf.default_screen);
ewmh_update_net_desktop_names(globalconf.default_screen);
widget_invalidate_cache(WIDGET_CACHE_WORKSPACES);
return 0;
}
/** Get all workspaces.
* \return A table with all workspaces.
*/
static int
luaA_workspace_get(lua_State *L)
{
workspace_t *workspace;
int i = 1;
lua_newtable(L);
for(workspace = globalconf.workspaces; workspace; workspace = workspace->next)
{
luaA_workspace_userdata_new(workspace);
lua_rawseti(L, -2, i++);
}
return 1;
}
/** Create a new workspace.
* \param A table with at least a name attribute.
* Optionnal attributes are: mwfact, ncol, nmaster and layout.
* \return A new workspace object.
*/
static int
luaA_workspace_new(lua_State *L)
{
workspace_t *workspace;
int ncol, nmaster;
const char *name, *lay;
double mwfact;
layout_t *layout;
luaA_checktable(L, 1);
name = luaA_name_init(L);
mwfact = luaA_getopt_number(L, 1, "mwfact", 0.5);
ncol = luaA_getopt_number(L, 1, "ncol", 1);
nmaster = luaA_getopt_number(L, 1, "nmaster", 1);
lay = luaA_getopt_string(L, 1, "layout", "tile");
layout = name_func_lookup(lay, LayoutList);
workspace = workspace_new(name,
layout,
mwfact, nmaster, ncol);
return luaA_workspace_userdata_new(workspace);
}
/** Set a workspace visible on a screen.
* \param A screen number.
*/
static int
luaA_workspace_screen_set(lua_State *L)
{
workspace_t **workspace = luaA_checkudata(L, 1, "workspace");
int screen = luaL_checknumber(L, 2) - 1;
luaA_checkscreen(screen);
workspace_view(*workspace, screen);
return 0;
}
/** Get the screen the workspace is visible on.
* \return A screen number of nil if the workspace is not visible.
*/
static int
luaA_workspace_screen_get(lua_State *L)
{
workspace_t **workspace = luaA_checkudata(L, 1, "workspace");
int screen = workspace_screen_get(*workspace);
if(screen < 0)
return 0;
lua_pushnumber(L, screen + 1);
return 1;
}
/** Give the focus to the latest focused client on a workspace.
*/
static int
luaA_workspace_focus_set(lua_State *L)
{
workspace_t **workspace = luaA_checkudata(L, 1, "workspace");
client_focus(focus_client_getcurrent(*workspace));
return 0;
}
/** Set the workspace master width factor. This value is used in various layouts to
* determine the size of the master window.
* \param The master width ratio value, between 0 and 1.
*/
static int
luaA_workspace_mwfact_set(lua_State *L)
{
workspace_t **workspace = luaA_checkudata(L, 1, "workspace");
double mwfact = luaL_checknumber(L, 2);
if(mwfact < 1 && mwfact > 0)
{
(*workspace)->mwfact = mwfact;
(*workspace)->need_arrange = true;
}
else
luaL_error(L, "bad value, must be between 0 and 1");
return 0;
}
/** Get the workspace master width factor.
* \return The master width ratio value.
*/
static int
luaA_workspace_mwfact_get(lua_State *L)
{
workspace_t **workspace = luaA_checkudata(L, 1, "workspace");
lua_pushnumber(L, (*workspace)->mwfact);
return 1;
}
/** Set the number of columns. This is used in various layouts to set the number
* of columns used to display non-master windows.
* \param The number of columns, at least 1.
*/
static int
luaA_workspace_ncol_set(lua_State *L)
{
workspace_t **workspace = luaA_checkudata(L, 1, "workspace");
int ncol = luaL_checknumber(L, 2);
if(ncol >= 1)
{
(*workspace)->ncol = ncol;
(*workspace)->need_arrange = true;
}
else
luaL_error(L, "bad value, must be greater than 1");
return 0;
}
/** Get the number of columns used to display non-master windows on this workspace.
* \return The number of column.
*/
static int
luaA_workspace_ncol_get(lua_State *L)
{
workspace_t **workspace = luaA_checkudata(L, 1, "workspace");
lua_pushnumber(L, (*workspace)->ncol);
return 1;
}
/** Set the number of master windows. This is used in various layouts to
* determine how many windows are in the master area.
* \param The number of master windows.
*/
static int
luaA_workspace_nmaster_set(lua_State *L)
{
workspace_t **workspace = luaA_checkudata(L, 1, "workspace");
int nmaster = luaL_checknumber(L, 2);
if(nmaster >= 0)
{
(*workspace)->nmaster = nmaster;
(*workspace)->need_arrange = true;
}
else
luaL_error(L, "bad value, must be greater than 0");
return 0;
}
/** Get the number of master windows of the workspace.
* \return The number of master windows.
*/
static int
luaA_workspace_nmaster_get(lua_State *L)
{
workspace_t **workspace = luaA_checkudata(L, 1, "workspace");
lua_pushnumber(L, (*workspace)->nmaster);
return 1;
}
/** Get the workspace name.
* \return The workspace name.
*/
static int
luaA_workspace_name_get(lua_State *L)
{
workspace_t **workspace = luaA_checkudata(L, 1, "workspace");
lua_pushstring(L, (*workspace)->name);
return 1;
}
/** Set the workspace name.
* \param A string with the new workspace name.
*/
static int
luaA_workspace_name_set(lua_State *L)
{
workspace_t **workspace = luaA_checkudata(L, 1, "workspace");
const char *name = luaL_checkstring(L, 2);
p_delete(&(*workspace)->name);
(*workspace)->name = a_strdup(name);
return 0;
}
/** Handle workspace garbage collection.
*/
static int
luaA_workspace_gc(lua_State *L)
{
workspace_t **workspace = luaA_checkudata(L, 1, "workspace");
workspace_unref(workspace);
*workspace = NULL;
return 0;
}
/** Get the visible workspace for a screen.
* \param A screen number.
*/
static int
luaA_workspace_visible_get(lua_State *L)
{
int screen = luaL_checknumber(L, 1) - 1;
luaA_checkscreen(screen);
if(globalconf.screens[screen].workspace)
return luaA_workspace_userdata_new(globalconf.screens[screen].workspace);
return 0;
}
/** Get the layout of the workspace.
* \return The layout name.
*/
static int
luaA_workspace_layout_get(lua_State *L)
{
workspace_t **workspace = luaA_checkudata(L, 1, "workspace");
const char *name = a_strdup(name_func_rlookup((*workspace)->layout, LayoutList));
lua_pushstring(L, name);
return 1;
}
/** Set the layout of the workspace.
* \param A layout name.
*/
static int
luaA_workspace_layout_set(lua_State *L)
{
workspace_t **workspace = luaA_checkudata(L, 1, "workspace");
const char *name = luaL_checkstring(L, 2);
layout_t *l = name_func_lookup(name, LayoutList);
if(l)
{
(*workspace)->layout = l;
(*workspace)->need_arrange = true;
}
else
luaL_error(L, "unknown layout: %s", name);
return 0;
}
/** Create a new userdata from a workspace.
* \param t The workspace.
* \return The luaA_settype return value.
*/
int
luaA_workspace_userdata_new(workspace_t *w)
{
workspace_t **ws = lua_newuserdata(globalconf.L, sizeof(workspace_t *));
*ws = w;
workspace_ref(ws);
return luaA_settype(globalconf.L, "workspace");
}
const struct luaL_reg awesome_workspace_methods[] =
{
{ "new", luaA_workspace_new },
{ "get", luaA_workspace_get},
{ "visible_get", luaA_workspace_visible_get },
{ NULL, NULL }
};
const struct luaL_reg awesome_workspace_meta[] =
{
{ "add", luaA_workspace_add },
{ "screen_set", luaA_workspace_screen_set },
{ "screen_get", luaA_workspace_screen_get },
{ "focus_set", luaA_workspace_focus_set },
{ "mwfact_set", luaA_workspace_mwfact_set },
{ "mwfact_get", luaA_workspace_mwfact_get },
{ "ncol_set", luaA_workspace_ncol_set },
{ "ncol_get", luaA_workspace_ncol_get },
{ "nmaster_set", luaA_workspace_nmaster_set },
{ "nmaster_get", luaA_workspace_nmaster_get },
{ "name_get", luaA_workspace_name_get },
{ "name_set", luaA_workspace_name_set },
{ "layout_get", luaA_workspace_layout_get },
{ "layout_set", luaA_workspace_layout_set },
{ "__eq", luaA_workspace_eq },
{ "__gc", luaA_workspace_gc },
{ "__tostring", luaA_workspace_tostring },
{ NULL, NULL },
};
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80