Replace tags by workspaces

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Julien Danjou 2008-06-09 16:30:46 +02:00
parent 244a02b2d6
commit 00f966ea04
34 changed files with 1099 additions and 1396 deletions

View File

@ -32,7 +32,7 @@ LAYOUTS += layouts/magnifier.c
LAYOUTS += layouts/magnifier.h LAYOUTS += layouts/magnifier.h
WIDGETS = WIDGETS =
WIDGETS += widgets/taglist.c WIDGETS += widgets/workspacelist.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 \
tag.c tag.h \ workspace.c workspace.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,7 +26,6 @@ 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,17 +26,13 @@ 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 by tags. Each window can be tagged with one or multiple Windows are grouped in workspacess.
tags. Selecting certain tags displays all windows with these tags.
awesome contains a small status bar which displays all available tags, the layout, awesome contains a small status bar which displays all available workspaces,
the title of the focused window, and a status text. A the layout, the title of the focused window, and a status text.
floating window is indicated with an empty circle and a maximized A 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 tags are indicated with a different color. The tags of title. The selected workspace is indicated with a different color.
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
@ -50,20 +46,12 @@ OPTIONS
DEFAULTS MOUSE BINDINGS DEFAULTS MOUSE BINDINGS
----------------------- -----------------------
*Button1* on tag name:: *Button1* on workspace name::
View tag. View workspace.
*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 tag. Switch to previous or next workspace.
*Mod4 + Button1* on client window:: *Mod4 + Button1* on client window::
Move window. Move window.
*Mod4 + Button3* on client window:: *Mod4 + Button3* on client window::
@ -101,12 +89,10 @@ 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 tag. View previous workspace.
*Mod4 + Right*:: *Mod4 + Right*::
View next tag. View next workspace.
*Mod4 \+ Control \+ space*:: *Mod4 \+ Control \+ space*::
Set client floating. Set client floating.
*Mod4 \+ Shift \+ c*:: *Mod4 \+ Shift \+ c*::
@ -116,13 +102,9 @@ DEFAULTS KEY BINDINGS
*Mod4 \+ Control \+ r*:: *Mod4 \+ Control \+ r*::
Restart awesome. Restart awesome.
*Mod4 + 1-9*:: *Mod4 + 1-9*::
Switch to tag 1-9. Switch to workspace 1-9.
*Mod4 \+ Control \+ 1-9*::
Toggle tag view.
*Mod4 \+ Shift \+ 1-9*:: *Mod4 \+ Shift \+ 1-9*::
Tag client with tag. Move client to workspace 1-9.
*Mod4 \+ Shift \+ Control \+ 1-9*::
Toggle tag on client.
CUSTOMIZATION CUSTOMIZATION
------------- -------------

View File

@ -52,7 +52,6 @@
#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,33 +21,25 @@ modkey = "Mod4"
layouts = { "tile", "tileleft", "tilebottom", "tiletop", "magnifier", "max", "spiral", "dwindle", "floating" } layouts = { "tile", "tileleft", "tilebottom", "tiletop", "magnifier", "max", "spiral", "dwindle", "floating" }
-- }}} -- }}}
-- {{{ Tags -- {{{ Workspaces
-- Define tags table -- Define workspaces table
tags = {} workspaces = {}
for s = 1, screen.count() do -- Create 9 workspaces
-- Each screen has its own tag table for i = 1, 9 do
tags[s] = {} workspaces[i] = workspace.new({ name = i })
-- Create 9 tags per screen workspaces[i]:add(s)
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 taglist widget -- Create a workspacelist widget
mytaglist = widget.new({ type = "taglist", name = "mytaglist" }) myworkspacelist = widget.new({ type = "workspacelist", name = "myworkspacelist" })
mytaglist:mouse({}, 1, function (object, tag) awful.tag.viewonly(tag) end) myworkspacelist:mouse({ }, 1, function (object, workspace) workspace:screen_set(mouse.screen_get()) end)
mytaglist:mouse({ modkey }, 1, function (object, tag) awful.client.toggletag(tag) end) myworkspacelist:mouse({ }, 4, awful.workspace.viewnext)
mytaglist:mouse({}, 3, function (object, tag) tag:view(not tag:isselected()) end) myworkspacelist:mouse({ }, 5, awful.workspace.viewprev)
mytaglist:mouse({ modkey }, 3, function (object, tag) awful.client.toggletag(tag) end) myworkspacelist:set("text_focus", "<bg color=\"#555555\"/> <title/> ")
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" })
@ -82,7 +74,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(mytaglist) mystatusbar:widget_add(myworkspacelist)
mystatusbar:widget_add(myiconbox) mystatusbar:widget_add(myiconbox)
mystatusbar:widget_add(mytasklist) mystatusbar:widget_add(mytasklist)
mystatusbar:widget_add(mytextbox) mystatusbar:widget_add(mytextbox)
@ -93,8 +85,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.tag.viewnext) awesome.mouse({ }, 4, awful.workspace.viewnext)
awesome.mouse({ }, 5, awful.tag.viewprev) awesome.mouse({ }, 5, awful.workspace.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)
@ -104,44 +96,20 @@ 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 = 0 keynumber = math.min(9, #workspaces);
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 ()
local screen = mouse.screen_get() workspaces[i]:screen_set(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 ()
local screen = mouse.screen_get() client.focus_get():workspace_set(workspaces[i])
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.tag.viewprev):add() keybinding.new({ modkey }, "Left", awful.workspace.viewprev):add()
keybinding.new({ modkey }, "Right", awful.tag.viewnext):add() keybinding.new({ modkey }, "Right", awful.workspace.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()
@ -161,12 +129,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.tag.incmwfact(0.05) end):add() keybinding.new({ modkey }, "l", function () awful.workspace.incmwfact(0.05) end):add()
keybinding.new({ modkey }, "h", function () awful.tag.incmwfact(-0.05) end):add() keybinding.new({ modkey }, "h", function () awful.workspace.incmwfact(-0.05) end):add()
keybinding.new({ modkey, "Shift" }, "h", function () awful.tag.incnmaster(1) end):add() keybinding.new({ modkey, "Shift" }, "h", function () awful.workspace.incnmaster(1) end):add()
keybinding.new({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end):add() keybinding.new({ modkey, "Shift" }, "l", function () awful.workspace.incnmaster(-1) end):add()
keybinding.new({ modkey, "Control" }, "h", function () awful.tag.incncol(1) end):add() keybinding.new({ modkey, "Control" }, "h", function () awful.workspace.incncol(1) end):add()
keybinding.new({ modkey, "Control" }, "l", function () awful.tag.incncol(1) end):add() keybinding.new({ modkey, "Control" }, "l", function () awful.workspace.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()
-- }}} -- }}}
@ -185,7 +153,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 awful.layout.get(c:screen_get()) ~= "magnifier" then if c:workspace_get():layout_get() ~= "magnifier" then
c:focus_set() c:focus_set()
end end
end end
@ -202,10 +170,10 @@ function hook_newclient(c)
end end
-- Hook function to execute when arranging the screen -- Hook function to execute when arranging the screen
-- (tag switch, new client, etc) -- (workspace switch, new client, etc)
function hook_arrange(screen) function hook_arrange(ws)
local layout = awful.layout.get(screen) local screen = ws:screen_get()
mylayoutbox[screen]:set("image", "@iconsdir@/layouts/" .. layout .. "w.png") mylayoutbox[screen]:set("image", "@iconsdir@/layouts/" .. ws:layout_get() .. "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 tag = tag local workspace = workspace
local mouse = mouse local mouse = mouse
local os = os local os = os
local table = table local table = table
@ -84,13 +84,7 @@ function client_moveresize(x, y, w, h)
end end
function screen_focus(i) function screen_focus(i)
local sel = client.focus_get() local s = mouse.screen_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
@ -98,136 +92,81 @@ function screen_focus(i)
elseif s > count then elseif s > count then
s = 1 s = 1
end end
screen.focus(s) local ws = screen.workspace_get(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 tag_setmwfact(i) function workspace_setmwfact(i)
local t = tag_selected() local t = workspace_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 tag_incmwfact(i) function workspace_incmwfact(i)
local t = tag_selected() local t = workspace_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 tag_setnmaster(i) function workspace_setnmaster(i)
local t = tag_selected() local t = workspace_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 tag_incnmaster(i) function workspace_incnmaster(i)
local t = tag_selected() local t = workspace_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 tag_setncol(i) function workspace_setncol(i)
local t = tag_selected() local t = workspace_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 tag_incncol(i) function workspace_incncol(i)
local t = tag_selected() local t = workspace_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
-- View no tag function workspace_viewidx(r)
function tag_viewnone() local workspaces = workspace.get()
local tags = tag.get(mouse.screen_get()) local sel = workspace.visible_get(mouse.screen_get())
for i, t in ipairs(tags) do for i, t in ipairs(workspaces) 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
tags[array_boundandcycle(tags, i + r)]:view(true) workspaces[array_boundandcycle(workspaces, i + r)]:screen_set(mouse.screen_get())
end end
end end
end end
-- View next tag -- View next workspace
function tag_viewnext() function workspace_viewnext()
return tag_viewidx(1) return workspace_viewidx(1)
end end
-- View previous tag -- View previous workspace
function tag_viewprev() function workspace_viewprev()
return tag_viewidx(-1) return workspace_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)
@ -250,18 +189,11 @@ function client_movetoscreen(c, s)
end end
end end
function layout_get(screen) -- Function to change the layout of the current workspace.
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 = tag_selected() local t = workspace.visible_get(mouse.screen_get())
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
@ -269,7 +201,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 = layout_get() local cur_layout = t: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
@ -278,9 +210,9 @@ function layout_inc(layouts, i)
end end
end end
-- function to set the layout of the current tag by name. -- function to set the layout of the current workspace by name.
function layout_set(layout) function layout_set(layout)
local t = tag_selected() local t = workspace.visible_get(mouse.screen_get())
if t then if t then
t:layout_set(layout) t:layout_set(layout)
end end
@ -340,30 +272,24 @@ function spawn(cmd)
return os.execute(cmd .. "&") return os.execute(cmd .. "&")
end end
-- Export tags function -- Export workspaces function
P.tag = P.workspace =
{ {
viewnone = tag_viewnone; viewprev = workspace_viewprev;
viewprev = tag_viewprev; viewnext = workspace_viewnext;
viewnext = tag_viewnext; setmwfact = workspace_setmwfact;
viewonly = tag_viewonly; incmwfact = workspace_incmwfact;
viewmore = tag_viewmore; setncol = workspace_setncol;
setmwfact = tag_setmwfact; incncol = workspace_incncol;
incmwfact = tag_incmwfact; setnmaster = workspace_setnmaster;
setncol = tag_setncol; incnmaster = workspace_incnmaster;
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;
movetotag = client_movetotag; movetoworkspace = client_movetoworkspace;
toggletag = client_toggletag;
togglefloating = client_togglefloating; togglefloating = client_togglefloating;
moveresize = client_moveresize; moveresize = client_moveresize;
movetoscreen = client_movetoscreen; movetoscreen = client_movetoscreen;
@ -374,7 +300,6 @@ P.screen =
} }
P.layout = P.layout =
{ {
get = layout_get;
set = layout_set; set = layout_set;
inc = layout_inc; inc = layout_inc;
} }

291
client.c
View File

@ -27,7 +27,7 @@
#include <xcb/shape.h> #include <xcb/shape.h>
#include "client.h" #include "client.h"
#include "tag.h" #include "workspace.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 tag /** Load windows properties, restoring client's workspace
* 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 tags is != than before. * \todo This may bug if number of workspacess 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, int screen) client_loadprops(client_t * c)
{ {
int i, ntags = 0; int i, nworkspaces = 0;
tag_t *tag; workspace_t *workspace;
char *prop = NULL; char *prop = NULL;
bool result = false; bool result = false;
xutil_intern_atom_request_t atom_q;
for(tag = globalconf.screens[screen].tags; tag; tag = tag->next) atom_q = xutil_intern_atom(globalconf.connection, &globalconf.atoms, "_AWESOME_PROPERTIES");
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, xutil_intern_atom_reply(globalconf.connection, &globalconf.atoms, atom_q),
xutil_intern_atom(globalconf.connection,
&globalconf.atoms,
"_AWESOME_PROPERTIES")),
&prop)) &prop))
{ {
for(i = 0, tag = globalconf.screens[screen].tags; tag && i < ntags && prop[i]; i++, tag = tag->next) for(i = 0, workspace = globalconf.workspaces; workspace && i < nworkspaces && prop[i]; i++, workspace = workspace->next)
if(prop[i] == '1') if(prop[i] == '1')
{ {
tag_client(c, tag); workspace_client_set(c, workspace);
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,44 +115,42 @@ window_isprotodel(xcb_window_t win)
return ret; return ret;
} }
/** Returns true if a client is tagged with one of the tags visibl /** Returns true if a client is on a workspace visible
* on any screen. * on any screen.
* \param c The client. * \param c The client.
* \return True if client is tagged, false otherwise. * \return True if client is visible, false otherwise.
*/ */
static bool static bool
client_isvisible_anyscreen(client_t *c) client_isvisible_anyscreen(client_t *c)
{ {
tag_t *tag; workspace_t *ws;
int screen; int screen;
if(c) if(c)
{
ws = workspace_client_get(c);
for(screen = 0; screen < globalconf.screens_info->nscreen; screen++) for(screen = 0; screen < globalconf.screens_info->nscreen; screen++)
for(tag = globalconf.screens[screen].tags; tag; tag = tag->next) if(globalconf.screens[screen].workspace == ws)
if(tag->selected && is_client_tagged(c, tag)) return true;
return true; }
return false; return false;
} }
/** Returns true if a client is tagged /** Returns true if a client is on the workspace visible on the specified
* with one of the tags of the specified screen. * 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)
{ {
tag_t *tag; if(c)
return (workspace_client_get(c) == globalconf.screens[screen].workspace);
if(c && 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.
@ -195,18 +193,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(c->screen, WIDGET_CACHE_CLIENTS); widget_invalidate_cache(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(globalconf.focus->client); luaA_client_userdata_new(c);
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(c->screen, WIDGET_CACHE_CLIENTS); widget_invalidate_cache(WIDGET_CACHE_CLIENTS);
} }
/** Ban client and unmap it /** Ban client and unmap it
@ -225,55 +223,40 @@ 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.
* \param screen Virtual screen number. * \return True if a window (even root).
* \return True if a window (even root) has received focus, false otherwise.
*/ */
bool bool
client_focus(client_t *c, int screen) client_focus(client_t *c)
{ {
int phys_screen; int phys_screen;
/* if c is NULL or invisible, take next client in the focus history */ if(!c)
if((!c || (c && (!client_isvisible(c, screen)))) return false;
&& !(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 */
{ client_unban(c);
/* unban the client before focusing or it will fail */ /* save sel in focus history */
client_unban(c); focus_client_push(c);
/* save sel in focus history */ xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_POINTER_ROOT,
focus_client_push(c); c->win, XCB_CURRENT_TIME);
xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_POINTER_ROOT, /* since we're dropping EnterWindow events and sometimes the window
c->win, XCB_CURRENT_TIME); * will appear under the mouse, grabbuttons */
/* since we're dropping EnterWindow events and sometimes the window window_grabbuttons(c->win, c->phys_screen);
* will appear under the mouse, grabbuttons */ phys_screen = c->phys_screen;
window_grabbuttons(c->win, 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. */
globalconf.screens[c->screen].need_arrange = true; workspace_client_get(c)->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(screen, WIDGET_CACHE_CLIENTS); widget_invalidate_cache(WIDGET_CACHE_CLIENTS);
return true; return true;
} }
@ -329,20 +312,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);
c->screen = screen_get_bycoord(globalconf.screens_info, screen, wgeom->x, wgeom->y); rscreen = 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 = c->screen; c->phys_screen = rscreen;
/* Initial values */ /* Initial values */
c->win = w; c->win = w;
@ -358,18 +341,16 @@ 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, screen))) if(!(retloadprops = client_loadprops(c)))
screen_client_moveto(c, screen, true); workspace_client_set(c, globalconf.screens[screen].workspace);
/* Then check clients hints */ /* Then check clients hints */
ewmh_check_client_hints(c); ewmh_check_client_hints(c);
/* check for transient and set tags like its parent */ /* check for transient and set on same workspace 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)))
for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next) workspace_client_set(c, workspace_client_get(t));
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)
@ -407,7 +388,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(c->screen, WIDGET_CACHE_CLIENTS); widget_invalidate_cache(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 */
@ -474,15 +455,16 @@ 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 new_screen; int screen, new_screen;
area_t area; workspace_t *ws;
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];
if(c->titlebar && !c->ismoving && !c->isfloating && layout != layout_floating) ws = workspace_client_get(c);
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);
@ -494,24 +476,12 @@ 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, c->screen, geometry.x, geometry.y); screen_get_bycoord(globalconf.screens_info, 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;
@ -522,7 +492,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
|| layout_get_current(new_screen) == layout_floating) || ws->layout == layout_floating)
{ {
titlebar_update_geometry_floating(c); titlebar_update_geometry_floating(c);
if(!c->ismax) if(!c->ismax)
@ -536,15 +506,12 @@ 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 && layout != layout_floating) if(!c->ismoving && !c->isfloating && ws->layout != layout_floating)
titlebar_update_geometry_floating(c); titlebar_update_geometry_floating(c);
return resized; return resized;
@ -567,9 +534,8 @@ 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);
} }
if(client_isvisible(c, c->screen)) workspace_client_get(c)->need_arrange = true;
globalconf.screens[c->screen].need_arrange = true; widget_invalidate_cache(WIDGET_CACHE_CLIENTS);
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
if(floating) if(floating)
{ {
c->oldlayer = c->layer; c->oldlayer = c->layer;
@ -588,20 +554,23 @@ 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, ntags = 0; int i = 0, nws = 0;
char *prop; char *prop;
tag_t *tag; workspace_t *workspace, *cws = workspace_client_get(c);
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(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next) for(workspace = globalconf.workspaces; workspace; workspace = workspace->next)
ntags++; nws++;
prop = p_new(char, ntags + 3); prop = p_new(char, nws + 3);
for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next, i++) for(workspace = globalconf.workspaces; workspace; workspace = workspace->next, i++)
prop[i] = is_client_tagged(c, tag) ? '1' : '0'; if(cws == workspace)
prop[i] = '1';
else
prop[i] = '0';
prop[i] = c->isfloating ? '1' : '0'; prop[i] = c->isfloating ? '1' : '0';
@ -628,8 +597,6 @@ 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);
@ -641,11 +608,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(NULL, c->screen); client_focus(focus_client_getcurrent(workspace_client_get(c)));
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);
@ -680,7 +647,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(c->screen, WIDGET_CACHE_CLIENTS); widget_invalidate_cache(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))
@ -916,7 +883,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);
globalconf.screens[c->screen].need_arrange = true; workspace_client_get(c)->need_arrange = true;
} }
/** Set the client border width and color. /** Set the client border width and color.
@ -941,64 +908,28 @@ luaA_client_border_set(lua_State *L)
return 0; return 0;
} }
/** Move the client to another screen. /** Set the client on the specified workspace.
* \param A screen number. * \param A workspace object.
*/ */
static int static int
luaA_client_screen_set(lua_State *L) luaA_client_workspace_set(lua_State *L)
{ {
client_t **c = luaA_checkudata(L, 1, "client"); client_t **c = luaA_checkudata(L, 1, "client");
int screen = luaL_checknumber(L, 2) - 1; workspace_t **workspace = luaA_checkudata(L, 2, "workspace");
luaA_checkscreen(screen); /* arrange old ws */
screen_client_moveto(*c, screen, true); workspace_client_get(*c)->need_arrange = true;
workspace_client_set(*c, *workspace);
return 0; return 0;
} }
/** Get the screen number the client is onto. /** Get the workspace the client is on.
* \return A screen number. * \return A workspace.
*/ */
static int static int
luaA_client_screen_get(lua_State *L) luaA_client_workspace_get(lua_State *L)
{ {
client_t **c = luaA_checkudata(L, 1, "client"); client_t **c = luaA_checkudata(L, 1, "client");
lua_pushnumber(L, 1 + (*c)->screen); return luaA_workspace_userdata_new(workspace_client_get(*c));
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.
@ -1026,7 +957,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 || layout_get_current((*c)->screen) == layout_floating) if((*c)->isfloating || workspace_client_get(*c)->layout == 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);
@ -1064,10 +995,9 @@ 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);
globalconf.screens[(*c)->screen].need_arrange = true; workspace_client_get(*c)->need_arrange = true;
globalconf.screens[(*swap)->screen].need_arrange = true; workspace_client_get(*swap)->need_arrange = true;
widget_invalidate_cache((*c)->screen, WIDGET_CACHE_CLIENTS); widget_invalidate_cache(WIDGET_CACHE_CLIENTS);
widget_invalidate_cache((*swap)->screen, WIDGET_CACHE_CLIENTS);
return 0; return 0;
} }
@ -1075,7 +1005,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, (*c)->screen); client_focus(*c);
return 0; return 0;
} }
@ -1191,6 +1121,7 @@ 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");
@ -1204,10 +1135,12 @@ luaA_client_titlebar_set(lua_State *L)
titlebar_ref(t); titlebar_ref(t);
titlebar_init(*c); titlebar_init(*c);
if((*c)->isfloating || layout_get_current((*c)->screen) == layout_floating) ws = workspace_client_get(*c);
if((*c)->isfloating || ws->layout == layout_floating)
titlebar_update_geometry_floating(*c); titlebar_update_geometry_floating(*c);
else else
globalconf.screens[(*c)->screen].need_arrange = true; ws->need_arrange = true;
return 0; return 0;
} }
@ -1258,11 +1191,9 @@ 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 },
{ "tag", luaA_client_tag }, { "workspace_set", luaA_client_workspace_set },
{ "istagged", luaA_client_istagged }, { "workspace_get", luaA_client_workspace_get },
{ "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 *, int); bool client_focus(client_t *);
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,7 +25,6 @@
#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"
@ -34,6 +33,7 @@
#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, c->screen, w->widget->button_press(w, ev, workspace_screen_get(workspace_client_get(c)),
c->titlebar, AWESOME_TYPE_TITLEBAR); c->titlebar, AWESOME_TYPE_TITLEBAR);
return 0; return 0;
} }
@ -181,9 +181,12 @@ 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)
@ -198,11 +201,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 || layout_get_current(c->screen) == layout_floating) if(c->isfloating || ws->layout == layout_floating)
client_resize(c, geometry, false); client_resize(c, geometry, false);
else else
{ {
globalconf.screens[c->screen].need_arrange = true; ws->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 */
@ -463,6 +466,7 @@ 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 */
@ -470,10 +474,11 @@ 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)))
globalconf.screens[c->screen].need_arrange = true; ws->need_arrange = true;
} }
else if (ev->atom == WM_NORMAL_HINTS) else if (ev->atom == WM_NORMAL_HINTS)
client_updatesizehints(c); client_updatesizehints(c);

46
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 "tag.h" #include "workspace.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;
tag_t *tag; workspace_t *workspace;
for(tag = globalconf.screens[phys_screen].tags; tag; tag = tag->next) for(workspace = globalconf.workspaces; workspace; workspace = workspace->next)
count++; count++;
xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
@ -202,16 +202,14 @@ 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;
tag_t *tag, **curtags = tags_get_current(phys_screen); workspace_t *workspace;
for(tag = globalconf.screens[phys_screen].tags; tag != curtags[0]; tag = tag->next) for(workspace = globalconf.workspaces; workspace; workspace = workspace->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
@ -219,14 +217,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;
tag_t *tag; workspace_t *workspace;
pos = buf; pos = buf;
len = 0; len = 0;
for(tag = globalconf.screens[phys_screen].tags; tag; tag = tag->next) for(workspace = globalconf.workspaces; workspace; workspace = workspace->next)
{ {
curr_size = a_strlen(tag->name); curr_size = a_strlen(workspace->name);
a_strcpy(pos, sizeof(buf), tag->name); a_strcpy(pos, sizeof(buf), workspace->name);
pos += curr_size + 1; pos += curr_size + 1;
len += curr_size + 1; len += curr_size + 1;
} }
@ -240,7 +238,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_get_current_client(phys_screen); client_t *sel = focus_client_getcurrent(phys_screen);
win = sel ? sel->win : XCB_NONE; win = sel ? sel->win : XCB_NONE;
@ -253,12 +251,11 @@ 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)
{ {
tag_t *tag; /* \todo support for sticky */
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)
{ {
@ -290,7 +287,8 @@ 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)
{ {
geometry = screen_area_get(c->screen, NULL, &globalconf.screens[c->screen].padding); screen = workspace_screen_get(workspace_client_get(c));
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;
@ -306,7 +304,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(c->screen, WIDGET_CACHE_CLIENTS); widget_invalidate_cache(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);
} }
@ -367,17 +365,21 @@ 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) if(ev->window == xcb_aux_get_screen(globalconf.connection, screen)->root)
tag_view_only_byindex(screen, ev->data.data32[0]); {
} for(i = 0, ws = globalconf.workspaces; i < ev->data.data32[0]; i++, ws = ws ->next);
globalconf.screens[screen].workspace = ws;
if(ev->type == net_close_window) }
}
else if(ev->type == net_close_window)
{ {
if((c = client_getbywin(ev->window))) if((c = client_getbywin(ev->window)))
client_kill(c); client_kill(c);

28
focus.c
View File

@ -21,7 +21,7 @@
#include "focus.h" #include "focus.h"
#include "cnode.h" #include "cnode.h"
#include "tag.h" #include "workspace.h"
extern awesome_t globalconf; extern awesome_t globalconf;
@ -61,38 +61,28 @@ focus_client_delete(client_t *c)
} }
static client_t * static client_t *
focus_get_latest_client_for_tags(tag_t **t, int nindex) focus_get_latest_client_for_workspace(workspace_t *ws, 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) if(node->client && !node->client->skip)
for(tags = t; *tags; tags++) if(workspace_client_get(node->client) == ws)
if(is_client_tagged(node->client, *tags)) if(i-- == nindex)
{ return node->client;
if(i == nindex)
return node->client;
else
i--;
}
return NULL; return NULL;
} }
/** Get the latest focused client on a screen. /** Get the latest focused client on a workspace.
* \param screen The virtual screen number. * \param ws The workspace.
* \return A pointer to an existing client. * \return A pointer to an existing client.
*/ */
client_t * client_t *
focus_get_current_client(int screen) focus_client_getcurrent(workspace_t *ws)
{ {
tag_t **curtags = tags_get_current(screen); return focus_get_latest_client_for_workspace(ws, 0);
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_get_current_client(int); client_t * focus_client_getcurrent(workspace_t *);
#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,13 +23,12 @@
#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 "layouts/magnifier.h" #include "workspace.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"
@ -37,26 +36,27 @@
extern awesome_t globalconf; extern awesome_t globalconf;
/** Arrange windows following current selected layout /** Arrange windows following current selected layout.
* \param screen the screen to arrange * \param ws The workspace to arrange.
*/ */
static void static void
arrange(int screen) arrange(workspace_t *ws)
{ {
client_t *c; client_t *c;
layout_t *curlay = layout_get_current(screen); int fscreen, screen = workspace_screen_get(ws), phys_screen = screen_virttophys(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)
if(client_isvisible(c, screen)) {
screen_client_moveto(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->screen == screen) else if(workspace_screen_get(cws) == -1)
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,26 +81,25 @@ arrange(int screen)
/* 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_get_current_client(screen))) && (c = focus_client_getcurrent(ws)))
client_focus(c, screen); client_focus(c);
} }
p_delete(&qp_r); p_delete(&qp_r);
} }
if(curlay) if(ws->layout)
curlay(screen); ws->layout(ws);
/* reset status */ /* reset status */
globalconf.screens[screen].need_arrange = false; ws->need_arrange = false;
/* call hook */ /* call hook */
lua_pushnumber(globalconf.L, screen + 1); luaA_workspace_userdata_new(ws);
luaA_dofunction(globalconf.L, globalconf.hooks.arrange, 1); luaA_dofunction(globalconf.L, globalconf.hooks.arrange, 1);
} }
/** Refresh the screen disposition /** Refresh the screens disposition.
* \return true if the screen was arranged, false otherwise
*/ */
void void
layout_refresh(void) layout_refresh(void)
@ -108,25 +107,8 @@ 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].need_arrange) if(globalconf.screens[screen].workspace && globalconf.screens[screen].workspace->need_arrange)
arrange(screen); arrange(globalconf.screens[screen].workspace);
}
/** 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,9 +25,6 @@
#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,18 +20,19 @@
*/ */
#include "screen.h" #include "screen.h"
#include "tag.h" #include "workspace.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(int screen, int shape) layout_fibonacci(workspace_t *ws, 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);
@ -88,15 +89,15 @@ layout_fibonacci(int screen, int shape)
} }
void void
layout_spiral(int screen) layout_spiral(workspace_t *ws)
{ {
layout_fibonacci(screen, 0); layout_fibonacci(ws, 0);
} }
void void
layout_dwindle(int screen) layout_dwindle(workspace_t *ws)
{ {
layout_fibonacci(screen, 1); layout_fibonacci(ws, 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,15 +20,16 @@
*/ */
#include "client.h" #include "client.h"
#include "tag.h" #include "workspace.h"
#include "layouts/floating.h" #include "layouts/floating.h"
extern awesome_t globalconf; extern awesome_t globalconf;
void void
layout_floating(int screen) layout_floating(workspace_t *ws)
{ {
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 "tag.h" #include "workspace.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(int screen) layout_magnifier(workspace_t *ws)
{ {
int n = 0; int n = 0;
client_t *c, *focus; client_t *c, *focus;
tag_t **curtags = tags_get_current(screen); int screen = workspace_screen_get(ws);
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_get_current_client(screen); focus = focus_client_getcurrent(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(int screen)
/* No windows is tiled, nothing to do. */ /* No windows is tiled, nothing to do. */
if(!focus) if(!focus)
goto bailout; return;
geometry.width = area.width * curtags[0]->mwfact; geometry.width = area.width * ws->mwfact;
geometry.height = area.height * curtags[0]->mwfact; geometry.height = area.height * ws->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(int screen)
/* No other clients. */ /* No other clients. */
if(!n) if(!n)
goto bailout; return;
geometry.x = area.x; geometry.x = area.x;
geometry.y = area.y; geometry.y = area.y;
@ -81,8 +81,5 @@ layout_magnifier(int screen)
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 "tag.h" #include "workspace.h"
#include "screen.h" #include "screen.h"
#include "client.h" #include "client.h"
#include "focus.h" #include "focus.h"
@ -28,12 +28,13 @@
extern awesome_t globalconf; extern awesome_t globalconf;
void void
layout_max(int screen) layout_max(workspace_t *ws)
{ {
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);
for(c = globalconf.clients; c; c = c->next) for(c = globalconf.clients; c; c = c->next)
if(IS_TILED(c, screen)) if(IS_TILED(c, screen))
@ -45,7 +46,7 @@ layout_max(int screen)
area.height += 2 * c->border; area.height += 2 * c->border;
} }
if((focus = focus_get_current_client(screen)) if((focus = focus_client_getcurrent(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 "tag.h" #include "workspace.h"
#include "client.h" #include "client.h"
#include "layouts/tile.h" #include "layouts/tile.h"
#include "common/util.h" #include "common/util.h"
@ -30,17 +30,18 @@
extern awesome_t globalconf; extern awesome_t globalconf;
static void static void
_tile(int screen, const position_t position) _tile(workspace_t *ws, 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 real_ncol = 1, win_by_col = 1, current_col = 0; int screen, 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,
@ -55,34 +56,34 @@ _tile(int screen, const position_t position)
wax = area.x; wax = area.x;
way = area.y; way = area.y;
masterwin = MIN(n, curtags[0]->nmaster); masterwin = MIN(n, ws->nmaster);
otherwin = MAX(n - masterwin, 0); otherwin = MAX(n - masterwin, 0);
if(curtags[0]->nmaster) if(ws->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 * curtags[0]->mwfact : waw; mw = otherwin ? waw * ws->mwfact : waw;
break; break;
default: default:
mh = otherwin ? wah * curtags[0]->mwfact : wah; mh = otherwin ? wah * ws->mwfact : wah;
mw = masterwin ? waw / masterwin : waw; mw = masterwin ? waw / masterwin : waw;
break; break;
} }
else else
mh = mw = 0; mh = mw = 0;
real_ncol = curtags[0]->ncol > 0 ? MIN(otherwin, curtags[0]->ncol) : MIN(otherwin, 1); real_ncol = ws->ncol > 0 ? MIN(otherwin, ws->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 < curtags[0]->nmaster) if(i < ws->nmaster)
{ {
switch(position) switch(position)
{ {
@ -116,8 +117,8 @@ _tile(int screen, const position_t position)
if(real_ncol) if(real_ncol)
win_by_col = otherwin / real_ncol; win_by_col = otherwin / real_ncol;
if((i - curtags[0]->nmaster) if((i - ws->nmaster)
&& (i - curtags[0]->nmaster) % win_by_col == 0 && (i - ws->nmaster) % win_by_col == 0
&& current_col < real_ncol - 1) && current_col < real_ncol - 1)
current_col++; current_col++;
@ -133,10 +134,10 @@ _tile(int screen, const position_t position)
geometry.width = (waw - mw) / real_ncol - 2 * c->border; geometry.width = (waw - mw) / real_ncol - 2 * c->border;
if(i == curtags[0]->nmaster || otherwin <= real_ncol || (i - curtags[0]->nmaster) % win_by_col == 0) if(i == ws->nmaster || otherwin <= real_ncol || (i - ws->nmaster) % win_by_col == 0)
geometry.y = way; geometry.y = way;
else else
geometry.y = way + ((i - curtags[0]->nmaster) % win_by_col) * (geometry.height + 2 * c->border); geometry.y = way + ((i - ws->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);
@ -152,10 +153,10 @@ _tile(int screen, const position_t position)
geometry.height = (wah - mh) / real_ncol - 2 * c->border; geometry.height = (wah - mh) / real_ncol - 2 * c->border;
if(i == curtags[0]->nmaster || otherwin <= real_ncol || (i - curtags[0]->nmaster) % win_by_col == 0) if(i == ws->nmaster || otherwin <= real_ncol || (i - ws->nmaster) % win_by_col == 0)
geometry.x = wax; geometry.x = wax;
else else
geometry.x = wax + ((i - curtags[0]->nmaster) % win_by_col) * (geometry.width + 2 * c->border); geometry.x = wax + ((i - ws->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);
@ -166,32 +167,30 @@ _tile(int screen, const position_t position)
} }
i++; i++;
} }
p_delete(&curtags);
} }
void void
layout_tile(int screen) layout_tile(workspace_t *ws)
{ {
_tile(screen, Right); _tile(ws, Right);
} }
void void
layout_tileleft(int screen) layout_tileleft(workspace_t *ws)
{ {
_tile(screen, Left); _tile(ws, Left);
} }
void void
layout_tilebottom(int screen) layout_tilebottom(workspace_t *ws)
{ {
_tile(screen, Bottom); _tile(ws, Bottom);
} }
void void
layout_tiletop(int screen) layout_tiletop(workspace_t *ws)
{ {
_tile(screen, Top); _tile(ws, 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

30
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 "tag.h" #include "workspace.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_tag_methods[]; extern const struct luaL_reg awesome_workspace_methods[];
extern const struct luaL_reg awesome_tag_meta[]; extern const struct luaL_reg awesome_workspace_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,16 +191,17 @@ luaA_screen_count(lua_State *L)
return 1; return 1;
} }
/** Give the focus to a screen. /** Get the workspace displayed on a screen.
* \param A screen number * \param A screen number.
*/ */
static int static int
luaA_screen_focus(lua_State *L) luaA_screen_workspace_get(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);
client_focus(NULL, screen); if(globalconf.screens[screen].workspace)
return luaA_workspace_userdata_new(globalconf.screens[screen].workspace);
return 0; return 0;
} }
@ -426,7 +427,7 @@ luaA_init(void)
{ {
{ "coords_get", luaA_screen_coords_get }, { "coords_get", luaA_screen_coords_get },
{ "count", luaA_screen_count }, { "count", luaA_screen_count },
{ "focus", luaA_screen_focus }, { "workspace_get", luaA_screen_workspace_get },
{ NULL, NULL } { NULL, NULL }
}; };
static const struct luaL_reg awesome_hooks_lib[] = static const struct luaL_reg awesome_hooks_lib[] =
@ -458,8 +459,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 tag */ /* Export workspace */
luaA_openlib(L, "tag", awesome_tag_methods, awesome_tag_meta); luaA_openlib(L, "workspace", awesome_workspace_methods, awesome_workspace_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);
@ -491,18 +492,13 @@ 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;
} }
/* Assure there's at least one tag */ /* \todo Assure there's at least one workspace */
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;
} }

114
mouse.c
View File

@ -27,7 +27,7 @@
#include "mouse.h" #include "mouse.h"
#include "screen.h" #include "screen.h"
#include "tag.h" #include "workspace.h"
#include "event.h" #include "event.h"
#include "client.h" #include "client.h"
#include "titlebar.h" #include "titlebar.h"
@ -126,11 +126,12 @@ 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(c->screen, screen_area_get(screen,
globalconf.screens[c->screen].statusbar, globalconf.screens[screen].statusbar,
&globalconf.screens[c->screen].padding); &globalconf.screens[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;
@ -140,7 +141,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, c->screen)) if(snapper != c && client_isvisible(c, screen))
{ {
snapper_geometry = snapper->geometry; snapper_geometry = snapper->geometry;
snapper_geometry.width += 2 * c->border; snapper_geometry.width += 2 * c->border;
@ -296,10 +297,9 @@ 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;
layout_t *layout; workspace_t *ws = workspace_client_get(c);
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,18 +334,16 @@ 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 || layout == layout_floating) if(c->isfloating || ws->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:
@ -359,7 +357,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 || layout == layout_floating) if(c->isfloating || ws->layout == layout_floating)
{ {
ev_motion = (xcb_motion_notify_event_t *) ev; ev_motion = (xcb_motion_notify_event_t *) ev;
@ -380,20 +378,24 @@ 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, c->screen, if((newscreen = screen_get_bycoord(globalconf.screens_info,
screen,
mquery_pointer_r->root_x, mquery_pointer_r->root_x,
mquery_pointer_r->root_y)) != c->screen) mquery_pointer_r->root_y)) != screen
&& globalconf.screens[newscreen].workspace)
{ {
screen_client_moveto(c, newscreen, true); ws->need_arrange = true;
globalconf.screens[c->screen].need_arrange = true; ws = globalconf.screens[newscreen].workspace;
globalconf.screens[newscreen].need_arrange = true; screen = workspace_screen_get(ws);
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);
globalconf.screens[c->screen].need_arrange = true; ws->need_arrange = true;
layout_refresh(); layout_refresh();
} }
p_delete(&mquery_pointer_r); p_delete(&mquery_pointer_r);
@ -408,8 +410,6 @@ mouse_client_move(client_t *c, int snap)
p_delete(&ev); p_delete(&ev);
break; break;
} }
}
}
} }
@ -577,62 +577,57 @@ 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 tag/layout to resize. * \param c A client on the workspace/layout to resize.
*/ */
static void static void
mouse_client_resize_tiled(client_t *c) mouse_client_resize_tiled(client_t *c)
{ {
xcb_screen_t *screen; xcb_screen_t *xscreen;
/* screen area modulo statusbar */ /* screen area modulo statusbar */
area_t area; area_t area;
/* current tag */ /* current workspace */
tag_t *tag; workspace_t *ws = workspace_client_get(c);
/* current layout */ int mouse_x, mouse_y, screen = workspace_screen_get(ws);
layout_t *layout;
int mouse_x, mouse_y;
size_t cursor = CurResize; size_t cursor = CurResize;
screen = xcb_aux_get_screen(globalconf.connection, c->phys_screen); xscreen = xcb_aux_get_screen(globalconf.connection, c->phys_screen);
tag = tags_get_current(c->screen)[0];
layout = tag->layout;
area = screen_area_get(tag->screen, area = screen_area_get(screen,
globalconf.screens[tag->screen].statusbar, globalconf.screens[screen].statusbar,
&globalconf.screens[tag->screen].padding); &globalconf.screens[screen].padding);
mouse_query_pointer(screen->root, &mouse_x, &mouse_y); mouse_query_pointer(xscreen->root, &mouse_x, &mouse_y);
/* select initial pointer position */ /* select initial pointer position */
if(layout == layout_tile) if(ws->layout == layout_tile)
{ {
mouse_x = area.x + area.width * tag->mwfact; mouse_x = area.x + area.width * ws->mwfact;
cursor = CurResizeH; cursor = CurResizeH;
} }
else if(layout == layout_tileleft) else if(ws->layout == layout_tileleft)
{ {
mouse_x = area.x + area.width * (1. - tag->mwfact); mouse_x = area.x + area.width * (1. - ws->mwfact);
cursor = CurResizeH; cursor = CurResizeH;
} }
else if(layout == layout_tilebottom) else if(ws->layout == layout_tilebottom)
{ {
mouse_y = area.y + area.height * tag->mwfact; mouse_y = area.y + area.height * ws->mwfact;
cursor = CurResizeV; cursor = CurResizeV;
} }
else if(layout == layout_tiletop) else if(ws->layout == layout_tiletop)
{ {
mouse_y = area.y + area.height * (1. - tag->mwfact); mouse_y = area.y + area.height * (1. - ws->mwfact);
cursor = CurResizeV; cursor = CurResizeV;
} }
else else
return; return;
/* grab the pointer */ /* grab the pointer */
if(!mouse_grab_pointer(screen->root, cursor)) if(!mouse_grab_pointer(xscreen->root, cursor))
return; return;
/* set pointer to the moveable border */ /* set pointer to the moveable border */
mouse_warp_pointer(screen->root, mouse_x, mouse_y); mouse_warp_pointer(xscreen->root, mouse_x, mouse_y);
xcb_aux_sync(globalconf.connection); xcb_aux_sync(globalconf.connection);
@ -645,20 +640,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(layout == layout_tile) if(ws->layout == layout_tile)
mwfact = fact_x; mwfact = fact_x;
else if(layout == layout_tileleft) else if(ws->layout == layout_tileleft)
mwfact = 1. - fact_x; mwfact = 1. - fact_x;
else if(layout == layout_tilebottom) else if(ws->layout == layout_tilebottom)
mwfact = fact_y; mwfact = fact_y;
else if(layout == layout_tiletop) else if(ws->layout == layout_tiletop)
mwfact = 1. - fact_y; mwfact = 1. - fact_y;
/* refresh layout */ /* refresh layout */
if(fabs(tag->mwfact - mwfact) >= 0.01) if(fabs(ws->mwfact - mwfact) >= 0.01)
{ {
tag->mwfact = mwfact; ws->mwfact = mwfact;
globalconf.screens[tag->screen].need_arrange = true; ws->need_arrange = true;
layout_refresh(); layout_refresh();
xcb_aux_sync(globalconf.connection); xcb_aux_sync(globalconf.connection);
} }
@ -679,16 +674,13 @@ 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;
tag_t **curtags; workspace_t *ws = workspace_client_get(c);
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(layout == layout_floating || c->isfloating) if(ws->layout == layout_floating || c->isfloating)
{ {
if(c->isfixed) if(c->isfixed)
return; return;
@ -697,16 +689,16 @@ mouse_client_resize(client_t *c, corner_t corner)
mouse_client_resize_floating(c, corner); mouse_client_resize_floating(c, corner);
} }
else if (layout == layout_tile || layout == layout_tileleft else if (ws->layout == layout_tile || ws->layout == layout_tileleft
|| layout == layout_tilebottom || layout == layout_tiletop) || ws->layout == layout_tilebottom || ws->layout == layout_tiletop)
{ {
screen = c->screen; screen = workspace_screen_get(ws);
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 <= curtags[0]->nmaster) return; if(n <= ws->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,6 +26,7 @@
#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;
@ -71,21 +72,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;
layout_t *layout; workspace_t *ws = workspace_client_get(c);
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(c->screen, *screen_geometry = screen_area_get(screen,
globalconf.screens[c->screen].statusbar, globalconf.screens[screen].statusbar,
&globalconf.screens[c->screen].padding); &globalconf.screens[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 || layout == layout_floating) if((client->isfloating || ws->layout == layout_floating)
&& client_isvisible(client, c->screen)) && client_isvisible(client, screen))
{ {
newgeometry = client->f_geometry; newgeometry = client->f_geometry;
newgeometry.width += 2 * client->border; newgeometry.width += 2 * client->border;
@ -119,7 +120,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, c->screen, c->border); newgeometry = placement_fix_offscreen(newgeometry, 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);
@ -133,6 +134,7 @@ 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);
@ -145,7 +147,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, c->screen, c->border); finalgeometry = placement_fix_offscreen(finalgeometry, screen, c->border);
finalgeometry = titlebar_geometry_remove(c->titlebar, finalgeometry); finalgeometry = titlebar_geometry_remove(c->titlebar, finalgeometry);
return finalgeometry; return finalgeometry;

131
screen.c
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,93 +121,80 @@ 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 destinatiuon screen number. * \param new_screen The new screen.
* \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, bool doresize) screen_client_moveto(client_t *c, int new_screen)
{ {
tag_t *tag; area_t from, to, new_geometry, new_f_geometry;
int old_screen = c->screen; int old_screen;
area_t from, to;
for(tag = globalconf.screens[old_screen].tags; tag; tag = tag->next) old_screen = screen_get_bycoord(globalconf.screens_info, c->phys_screen,
untag_client(c, tag); c->geometry.x, c->geometry.y);
c->screen = new_screen; /* nothing to do */
if(old_screen == new_screen)
return;
/* tag client with new screen tags */ new_f_geometry = c->f_geometry;
tag_client_with_current_selected(c);
/* resize the windows if it's floating */ from = screen_area_get(old_screen, NULL, NULL);
if(doresize && old_screen != c->screen) to = screen_area_get(new_screen, NULL, NULL);
/* compute new coords in new screen */
new_f_geometry.x = (c->f_geometry.x - from.x) + to.x;
new_f_geometry.y = (c->f_geometry.y - from.y) + to.y;
/* check that new coords are still in the screen */
if(new_f_geometry.width > to.width)
new_f_geometry.width = to.width;
if(new_f_geometry.height > to.height)
new_f_geometry.height = to.height;
if(new_f_geometry.x + new_f_geometry.width >= to.x + to.width)
new_f_geometry.x = to.x + to.width - new_f_geometry.width - 2 * c->border;
if(new_f_geometry.y + new_f_geometry.height >= to.y + to.height)
new_f_geometry.y = to.y + to.height - new_f_geometry.height - 2 * c->border;
if(c->ismax)
{ {
area_t new_geometry, new_f_geometry; new_geometry = c->geometry;
new_f_geometry = c->f_geometry;
to = screen_area_get(c->screen, NULL, NULL);
from = screen_area_get(old_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_geometry.x = (c->geometry.x - from.x) + to.x;
new_f_geometry.y = (c->f_geometry.y - from.y) + to.y; new_geometry.y = (c->geometry.y - from.y) + to.y;
/* check that new coords are still in the screen */ /* check that new coords are still in the screen */
if(new_f_geometry.width > to.width) if(new_geometry.width > to.width)
new_f_geometry.width = to.width; new_geometry.width = to.width;
if(new_f_geometry.height > to.height) if(new_geometry.height > to.height)
new_f_geometry.height = to.height; new_geometry.height = to.height;
if(new_f_geometry.x + new_f_geometry.width >= to.x + to.width) if(new_geometry.x + new_geometry.width >= to.x + to.width)
new_f_geometry.x = to.x + to.width - new_f_geometry.width - 2 * c->border; new_geometry.x = to.x + to.width - new_geometry.width - 2 * c->border;
if(new_f_geometry.y + new_f_geometry.height >= to.y + to.height) if(new_geometry.y + new_geometry.height >= to.y + to.height)
new_f_geometry.y = to.y + to.height - new_f_geometry.height - 2 * c->border; new_geometry.y = to.y + to.height - new_geometry.height - 2 * c->border;
if(c->ismax) /* compute new coords for max in new screen */
{ c->m_geometry.x = (c->m_geometry.x - from.x) + to.x;
new_geometry = c->geometry; c->m_geometry.y = (c->m_geometry.y - from.y) + to.y;
/* compute new coords in new screen */ /* check that new coords are still in the screen */
new_geometry.x = (c->geometry.x - from.x) + to.x; if(c->m_geometry.width > to.width)
new_geometry.y = (c->geometry.y - from.y) + to.y; c->m_geometry.width = to.width;
if(c->m_geometry.height > to.height)
c->m_geometry.height = to.height;
if(c->m_geometry.x + c->m_geometry.width >= to.x + to.width)
c->m_geometry.x = to.x + to.width - c->m_geometry.width - 2 * c->border;
if(c->m_geometry.y + c->m_geometry.height >= to.y + to.height)
c->m_geometry.y = to.y + to.height - c->m_geometry.height - 2 * c->border;
/* check that new coords are still in the screen */ client_resize(c, new_geometry, false);
if(new_geometry.width > to.width)
new_geometry.width = to.width;
if(new_geometry.height > to.height)
new_geometry.height = to.height;
if(new_geometry.x + new_geometry.width >= to.x + to.width)
new_geometry.x = to.x + to.width - new_geometry.width - 2 * c->border;
if(new_geometry.y + new_geometry.height >= to.y + to.height)
new_geometry.y = to.y + to.height - new_geometry.height - 2 * c->border;
/* compute new coords for max in new screen */
c->m_geometry.x = (c->m_geometry.x - from.x) + to.x;
c->m_geometry.y = (c->m_geometry.y - from.y) + to.y;
/* check that new coords are still in the screen */
if(c->m_geometry.width > to.width)
c->m_geometry.width = to.width;
if(c->m_geometry.height > to.height)
c->m_geometry.height = to.height;
if(c->m_geometry.x + c->m_geometry.width >= to.x + to.width)
c->m_geometry.x = to.x + to.width - c->m_geometry.width - 2 * c->border;
if(c->m_geometry.y + c->m_geometry.height >= to.y + to.height)
c->m_geometry.y = to.y + to.height - c->m_geometry.height - 2 * c->border;
client_resize(c, new_geometry, false);
}
/* if floating, move to this new coords */
else if(c->isfloating)
client_resize(c, new_f_geometry, false);
/* otherwise just register them */
else
{
c->f_geometry = new_f_geometry;
globalconf.screens[old_screen].need_arrange = true;
globalconf.screens[c->screen].need_arrange = true;
}
} }
/* if floating, move to this new coords */
else if(c->isfloating)
client_resize(c, new_f_geometry, false);
/* otherwise just register them */
else
c->f_geometry = new_f_geometry;
} }
// 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, bool); void screen_client_moveto(client_t *, 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

@ -24,7 +24,6 @@
#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"
@ -80,7 +79,8 @@ 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;
globalconf.screens[statusbar->screen].need_arrange = true; if(globalconf.screens[statusbar->screen].workspace)
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,7 +412,8 @@ 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);
globalconf.screens[i].need_arrange = true; if(globalconf.screens[s->screen].workspace)
globalconf.screens[s->screen].workspace->need_arrange = true;
return 0; return 0;
} }

View File

@ -50,6 +50,8 @@ 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;
@ -58,8 +60,7 @@ 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 _tag_t tag_t; typedef struct workspace_client_node_t workspace_client_node_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;
@ -279,8 +280,6 @@ struct client_t
client_t *prev, *next; client_t *prev, *next;
/** 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 */
@ -299,18 +298,14 @@ struct client_node_t
client_node_t *prev, *next; client_node_t *prev, *next;
}; };
/** Tag type */ /** Workspace type */
struct _tag_t struct workspace_t
{ {
/** Ref count */ /** Ref count */
int refcount; int refcount;
/** Tag name */ /** Tag name */
char *name; char *name;
/** Screen */ /** Current workspace layout */
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;
@ -318,17 +313,19 @@ struct _tag_t
int nmaster; int nmaster;
/** Number of columns in tile layout */ /** Number of columns in tile layout */
int ncol; int ncol;
/** Next and previous tags */ /** True if we need to arrange() */
tag_t *prev, *next; bool need_arrange;
/** Next and previous workspaces */
workspace_t *prev, *next;
}; };
/** Tag client link type */ /** Tag client link type */
struct tag_client_node_t struct workspace_client_node_t
{ {
tag_t *tag; workspace_t *workspace;
client_t *client; client_t *client;
/** Next and previous tag_client_nodes */ /** Next and previous workspace_client_nodes */
tag_client_node_t *prev, *next; workspace_client_node_t *prev, *next;
}; };
/** Padding type */ /** Padding type */
@ -344,16 +341,15 @@ 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 */
@ -402,8 +398,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 tags and clients */ /** Link between workspaces and clients */
tag_client_node_t *tclink; workspace_client_node_t *wclink;
/** Command line passed to awesome */ /** Command line passed to awesome */
char *argv; char *argv;
/** Last XMotionEvent coords */ /** Last XMotionEvent coords */
@ -442,6 +438,8 @@ 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
View File

@ -1,564 +0,0 @@
/*
* 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

@ -28,6 +28,7 @@
#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;
@ -110,7 +111,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,
c->screen, c->titlebar->position, workspace_screen_get(workspace_client_get(c)), 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,24 +248,25 @@ 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 screen, int flags) widget_invalidate_cache(int flags)
{ {
statusbar_t *statusbar; statusbar_t *statusbar;
widget_node_t *widget; widget_node_t *widget;
int screen;
for(statusbar = globalconf.screens[screen].statusbar; for(screen = 0; screen < globalconf.screens_info->nscreen; screen++)
statusbar; for(statusbar = globalconf.screens[screen].statusbar;
statusbar = statusbar->next) statusbar;
for(widget = statusbar->widgets; widget; widget = widget->next) statusbar = statusbar->next)
if(widget->widget->cache_flags & flags) for(widget = statusbar->widgets; widget; widget = widget->next)
{ if(widget->widget->cache_flags & flags)
statusbar->need_update = true; {
break; statusbar->need_update = true;
} break;
}
} }
/** Set a statusbar needs update because it has widget, or redraw a titlebar. /** Set a statusbar needs update because it has widget, or redraw a titlebar.

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_TAGS 1<<2 #define WIDGET_CACHE_WORKSPACES 1<<2
#define WIDGET_CACHE_ALL (WIDGET_CACHE_CLIENTS | WIDGET_CACHE_LAYOUTS | WIDGET_CACHE_TAGS) #define WIDGET_CACHE_ALL (WIDGET_CACHE_CLIENTS | WIDGET_CACHE_LAYOUTS | WIDGET_CACHE_WORKSPACES)
typedef widget_t *(widget_constructor_t)(alignment_t); typedef widget_t *(widget_constructor_t)(alignment_t);
void widget_invalidate_cache(int, int); void widget_invalidate_cache(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 taglist_new; widget_constructor_t workspacelist_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

@ -25,7 +25,6 @@
#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"
@ -34,7 +33,7 @@ extern awesome_t globalconf;
typedef enum typedef enum
{ {
ShowFocus, ShowFocus,
ShowTags, ShowWorkspace,
ShowAll, ShowAll,
} showclient_t; } showclient_t;
@ -54,11 +53,11 @@ tasklist_isvisible(client_t *c, int screen, showclient_t show)
switch(show) switch(show)
{ {
case ShowAll: case ShowAll:
return (c->screen == screen); return true;
case ShowTags: case ShowWorkspace:
return client_isvisible(c, screen); return client_isvisible(c, screen);
case ShowFocus: case ShowFocus:
return (c == focus_get_current_client(screen)); return (c == focus_client_getcurrent(screen));
} }
return false; return false;
} }
@ -263,8 +262,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, "tags")) if(!a_strcmp(new_value, "workspace"))
d->show = ShowTags; d->show = ShowWorkspace;
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"))
@ -296,7 +295,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 = ShowTags; d->show = ShowWorkspace;
/* Set cache property */ /* Set cache property */
w->cache_flags = WIDGET_CACHE_CLIENTS; w->cache_flags = WIDGET_CACHE_CLIENTS;

View File

@ -1,6 +1,7 @@
/* /*
* taglist.c - tag list widget * workspacelist.c - workspace 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
@ -21,7 +22,7 @@
#include "client.h" #include "client.h"
#include "widget.h" #include "widget.h"
#include "tag.h" #include "workspace.h"
#include "lua.h" #include "lua.h"
#include "event.h" #include "event.h"
#include "common/markup.h" #include "common/markup.h"
@ -29,26 +30,26 @@
extern awesome_t globalconf; extern awesome_t globalconf;
typedef struct taglist_drawn_area_t taglist_drawn_area_t; typedef struct workspacelist_drawn_area_t workspacelist_drawn_area_t;
struct taglist_drawn_area_t struct workspacelist_drawn_area_t
{ {
void *object; void *object;
area_t *area; area_t *area;
taglist_drawn_area_t *next, *prev; workspacelist_drawn_area_t *next, *prev;
}; };
DO_SLIST(taglist_drawn_area_t, taglist_drawn_area, p_delete); DO_SLIST(workspacelist_drawn_area_t, workspacelist_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;
taglist_drawn_area_t *drawn_area; workspacelist_drawn_area_t *drawn_area;
} taglist_data_t; } workspacelist_data_t;
static char * static char *
tag_markup_parse(tag_t *t, const char *str, ssize_t len) workspace_markup_parse(workspace_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);
@ -72,89 +73,88 @@ tag_markup_parse(tag_t *t, const char *str, ssize_t len)
return ret; return ret;
} }
/** Check if at least one client is tagged with tag number t and is on screen /** Check if at least one client is on the workspace.
* screen * \param ws The workspace.
* \param t tag * \return True or false.
* \return true or false
*/ */
static bool static bool
tag_isoccupied(tag_t *t) workspace_isoccupied(workspace_t *ws)
{ {
client_t *c; client_t *c;
for(c = globalconf.clients; c; c = c->next) for(c = globalconf.clients; c; c = c->next)
if(is_client_tagged(c, t) && !c->skip) if(workspace_client_get(c) == ws)
return true; return true;
return false; return false;
} }
static bool static bool
tag_isurgent(tag_t *t) workspace_isurgent(workspace_t *ws)
{ {
client_t *c; client_t *c;
for(c = globalconf.clients; c; c = c->next) for(c = globalconf.clients; c; c = c->next)
if(is_client_tagged(c, t) && c->isurgent) if(c->isurgent && workspace_client_get(c) == ws)
return true; return true;
return false; return false;
} }
static char * static char *
taglist_text_get(tag_t *tag, taglist_data_t *data) workspacelist_text_get(workspace_t *ws, screen_t *screen, workspacelist_data_t *data)
{ {
if(tag->selected) if(screen->workspace == ws)
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
taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w, workspacelist_draw(draw_context_t *ctx, int screen,
int offset, widget_node_t *w,
int used __attribute__ ((unused)), int offset,
void *object) int used __attribute__ ((unused)),
void *object)
{ {
tag_t *tag; workspace_t *ws;
taglist_data_t *data = w->widget->data; workspacelist_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;
taglist_drawn_area_t *tda; workspacelist_drawn_area_t *tda;
w->area.width = w->area.y = 0; w->area.width = w->area.y = 0;
/* Lookup for our taglist_drawn_area. /* Lookup for our workspacelist_drawn_area.
* This will be used to store area where we draw tag list for each object. */ * This will be used to store area where we draw ws 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(taglist_drawn_area_t, 1); tda = p_new(workspacelist_drawn_area_t, 1);
tda->object = object; tda->object = object;
taglist_drawn_area_list_push(&data->drawn_area, tda); workspacelist_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(tag = vscreen->tags; tag; tag = tag->next, i++) for(ws = globalconf.workspaces; ws; ws = ws->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] = taglist_text_get(tag, data); text[i] = workspacelist_text_get(ws, &globalconf.screens[screen], data);
text[i] = tag_markup_parse(tag, text[i], a_strlen(text[i])); text[i] = workspace_markup_parse(ws, 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 || tag->selected || tag_isoccupied(tag)) if (data->show_empty || workspace_isoccupied(ws))
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 @@ taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w,
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, tag = vscreen->tags, i = 0; for(area = tda->area, ws = globalconf.workspaces, i = 0;
tag && area; ws && area;
tag = tag->next, area = area->next, i++) ws = ws->next, area = area->next, i++)
{ {
if (!data->show_empty && !tag->selected && !tag_isoccupied(tag)) if (!data->show_empty && !workspace_isoccupied(ws))
continue; continue;
area->x = w->area.x + prev_width; area->x = w->area.x + prev_width;
@ -176,13 +176,12 @@ taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w,
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(tag_isoccupied(tag)) if(workspace_isoccupied(ws))
{ {
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, draw_rectangle(ctx, rectangle, 1.0, false, ctx->fg);
sel && is_client_tagged(sel, tag), ctx->fg);
} }
} }
@ -200,18 +199,17 @@ taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w,
* \param type The type object. * \param type The type object.
*/ */
static void static void
taglist_button_press(widget_node_t *w, workspacelist_button_press(widget_node_t *w,
xcb_button_press_event_t *ev, xcb_button_press_event_t *ev,
int screen, int screen __attribute__ ((unused)),
void *object, void *object,
awesome_type_t type) awesome_type_t type)
{ {
screen_t *vscreen = &globalconf.screens[screen];
button_t *b; button_t *b;
taglist_data_t *data = w->widget->data; workspacelist_data_t *data = w->widget->data;
taglist_drawn_area_t *tda; workspacelist_drawn_area_t *tda;
area_t *area; area_t *area;
tag_t *tag; workspace_t *ws;
/* 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);
@ -219,22 +217,22 @@ taglist_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(tag = vscreen->tags; tag && area; tag = tag->next, area = area->next) for(ws = globalconf.workspaces; ws && area; ws = ws->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 || tag->selected || tag_isoccupied(tag)) ) && (data->show_empty || workspace_isoccupied(ws)) )
{ {
luaA_pushpointer(object, type); luaA_pushpointer(object, type);
luaA_tag_userdata_new(tag); luaA_workspace_userdata_new(ws);
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
taglist_tell(widget_t *widget, const char *property, const char *new_value) workspacelist_tell(widget_t *widget, const char *property, const char *new_value)
{ {
taglist_data_t *d = widget->data; workspacelist_data_t *d = widget->data;
if(!a_strcmp(property, "text_normal")) if(!a_strcmp(property, "text_normal"))
{ {
@ -260,26 +258,26 @@ taglist_tell(widget_t *widget, const char *property, const char *new_value)
} }
widget_t * widget_t *
taglist_new(alignment_t align) workspacelist_new(alignment_t align)
{ {
widget_t *w; widget_t *w;
taglist_data_t *d; workspacelist_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 = taglist_draw; w->draw = workspacelist_draw;
w->button_press = taglist_button_press; w->button_press = workspacelist_button_press;
w->tell = taglist_tell; w->tell = workspacelist_tell;
w->data = d = p_new(taglist_data_t, 1); w->data = d = p_new(workspacelist_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_TAGS | WIDGET_CACHE_CLIENTS; w->cache_flags = WIDGET_CACHE_WORKSPACES | WIDGET_CACHE_CLIENTS;
return w; return w;
} }

515
workspace.c Normal file
View File

@ -0,0 +1,515 @@
/*
* 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

View File

@ -1,5 +1,5 @@
/* /*
* tag.h - tag management header * workspace.h - workspace management header
* *
* Copyright © 2007-2008 Julien Danjou <julien@danjou.info> * Copyright © 2007-2008 Julien Danjou <julien@danjou.info>
* *
@ -19,8 +19,8 @@
* *
*/ */
#ifndef AWESOME_TAG_H #ifndef AWESOME_WORKSPACE_H
#define AWESOME_TAG_H #define AWESOME_WORKSPACE_H
#include "structs.h" #include "structs.h"
#include "common/refcount.h" #include "common/refcount.h"
@ -29,28 +29,26 @@
#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 */
tag_t * tag_new(const char *, layout_t *, double, int, int); workspace_t * workspace_new(const char *, layout_t *, double, int, int);
static inline void static inline void
tag_delete(tag_t **tag) workspace_delete(workspace_t **workspace)
{ {
p_delete(&(*tag)->name); p_delete(&(*workspace)->name);
p_delete(tag); p_delete(workspace);
} }
tag_t ** tags_get_current(int); void workspace_client_set(client_t *, workspace_t *);
void tag_client(client_t *, tag_t *); workspace_t * workspace_client_get(client_t *);
void untag_client(client_t *, tag_t *); void workspace_client_remove(client_t *);
bool is_client_tagged(client_t *, tag_t *); int workspace_screen_get(workspace_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 *);
DO_RCNT(tag_t, tag, tag_delete) int luaA_workspace_userdata_new(workspace_t *);
DO_SLIST(tag_t, tag, tag_delete)
DO_SLIST(tag_client_node_t, tag_client_node, p_delete) DO_RCNT(workspace_t, workspace, workspace_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