From 00f966ea047ec4f464770af03044602ac5781c2c Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Mon, 9 Jun 2008 16:30:46 +0200 Subject: [PATCH] Replace tags by workspaces Signed-off-by: Julien Danjou --- Makefile.am | 4 +- awesome-client.1.txt | 1 - awesome.1.txt | 42 +- awesome.c | 1 - awesomerc.lua.in | 100 ++--- awful.lua | 165 ++------ client.c | 291 +++++-------- client.h | 2 +- event.c | 15 +- ewmh.c | 46 +- focus.c | 28 +- focus.h | 2 +- layout.c | 58 +-- layout.h | 3 - layouts/fibonacci.c | 13 +- layouts/floating.c | 5 +- layouts/magnifier.c | 19 +- layouts/max.c | 11 +- layouts/tile.c | 51 ++- lua.c | 30 +- mouse.c | 114 +++-- placement.c | 20 +- screen.c | 131 +++--- screen.h | 2 +- statusbar.c | 7 +- structs.h | 44 +- tag.c | 564 ------------------------- titlebar.c | 3 +- widget.c | 23 +- widget.h | 8 +- widgets/tasklist.c | 15 +- widgets/{taglist.c => workspacelist.c} | 128 +++--- workspace.c | 515 ++++++++++++++++++++++ tag.h => workspace.h | 34 +- 34 files changed, 1099 insertions(+), 1396 deletions(-) delete mode 100644 tag.c rename widgets/{taglist.c => workspacelist.c} (63%) create mode 100644 workspace.c rename tag.h => workspace.h (63%) diff --git a/Makefile.am b/Makefile.am index dcec6e15..a6b8347e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,7 +32,7 @@ LAYOUTS += layouts/magnifier.c LAYOUTS += layouts/magnifier.h WIDGETS = -WIDGETS += widgets/taglist.c +WIDGETS += widgets/workspacelist.c WIDGETS += widgets/textbox.c WIDGETS += widgets/iconbox.c WIDGETS += widgets/progressbar.c @@ -128,7 +128,7 @@ awesome_SOURCES = \ layout.c layout.h \ keybinding.c keybinding.h \ awesome.c \ - tag.c tag.h \ + workspace.c workspace.h \ lua.c lua.h \ screen.c screen.h \ statusbar.c statusbar.h \ diff --git a/awesome-client.1.txt b/awesome-client.1.txt index 82abab59..11474c93 100644 --- a/awesome-client.1.txt +++ b/awesome-client.1.txt @@ -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 collected lines into awesome with an according immediate execution. - SEE ALSO -------- awesome(1) awesomerc(5) diff --git a/awesome.1.txt b/awesome.1.txt index 7d106a9e..50edfcb0 100644 --- a/awesome.1.txt +++ b/awesome.1.txt @@ -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 former or as a rectangular fractal for the later. -Windows are grouped by tags. Each window can be tagged with one or multiple -tags. Selecting certain tags displays all windows with these tags. +Windows are grouped in workspacess. -awesome contains a small status bar which displays all available tags, the layout, -the title of the focused window, and a status text. A -floating window is indicated with an empty circle and a maximized +awesome contains a small status bar which displays all available workspaces, +the layout, the title of the focused window, and a status text. +A floating window is indicated with an empty circle and a maximized floating window is indicated with a circle square before the windows -title. The selected tags are indicated with a different color. The tags of -the focused window are indicated with a filled square in the top left -corner. The tags which are applied to one or more windows are indicated -with an empty square in the top left corner. +title. The selected workspace is indicated with a different color. awesome can draw a small border around windows to indicate the focus state. OPTIONS @@ -50,20 +46,12 @@ OPTIONS DEFAULTS MOUSE BINDINGS ----------------------- -*Button1* on tag name:: - View tag. -*Mod4 + Button1* on tag name:: - Tag current client with this tag. -*Button3* on tag name:: - Add this tag to current view. -*Mod4 + Button3* on tag name:: - Toggle this tag for client. -*Button4*, *Button5* on tag name:: - Switch to previous or next tag. +*Button1* on workspace name:: + View workspace. *Button1*, *Button3*, *Button4*, *Button5* on layout symbol:: Switch to previous or next layout. *Button4*, *Button5* on root window:: - Switch to previous or next tag. + Switch to previous or next workspace. *Mod4 + Button1* on client window:: Move window. *Mod4 + Button3* on client window:: @@ -101,12 +89,10 @@ DEFAULTS KEY BINDINGS Increase number of columns for non-master windows by 1. *Mod4 \+ Control \+ l*:: Decrease number of columns for non-master windows by 1. -*Mod4 + Escape*:: - View previously selected tag. *Mod4 + Left*:: - View previous tag. + View previous workspace. *Mod4 + Right*:: - View next tag. + View next workspace. *Mod4 \+ Control \+ space*:: Set client floating. *Mod4 \+ Shift \+ c*:: @@ -116,13 +102,9 @@ DEFAULTS KEY BINDINGS *Mod4 \+ Control \+ r*:: Restart awesome. *Mod4 + 1-9*:: - Switch to tag 1-9. -*Mod4 \+ Control \+ 1-9*:: - Toggle tag view. + Switch to workspace 1-9. *Mod4 \+ Shift \+ 1-9*:: - Tag client with tag. -*Mod4 \+ Shift \+ Control \+ 1-9*:: - Toggle tag on client. + Move client to workspace 1-9. CUSTOMIZATION ------------- diff --git a/awesome.c b/awesome.c index ae8d4004..0b7f565b 100644 --- a/awesome.c +++ b/awesome.c @@ -52,7 +52,6 @@ #include "client.h" #include "focus.h" #include "ewmh.h" -#include "tag.h" #include "dbus.h" #include "statusbar.h" #include "common/socket.h" diff --git a/awesomerc.lua.in b/awesomerc.lua.in index b957268b..491dac8a 100644 --- a/awesomerc.lua.in +++ b/awesomerc.lua.in @@ -21,33 +21,25 @@ modkey = "Mod4" layouts = { "tile", "tileleft", "tilebottom", "tiletop", "magnifier", "max", "spiral", "dwindle", "floating" } -- }}} --- {{{ Tags --- Define tags table -tags = {} -for s = 1, screen.count() do - -- Each screen has its own tag table - tags[s] = {} - -- Create 9 tags per screen - for tagnumber = 1, 9 do - tags[s][tagnumber] = tag.new({ name = tagnumber }) - -- Add tags to screen one by one - tags[s][tagnumber]:add(s) - end - -- I'm sure you want to see at least one tag. - tags[s][1]:view(true) +-- {{{ Workspaces +-- Define workspaces table +workspaces = {} +-- Create 9 workspaces +for i = 1, 9 do + workspaces[i] = workspace.new({ name = i }) + workspaces[i]:add(s) end +-- I'm sure you want to see at least one workspace +workspaces[1]:screen_set(1) -- }}} -- {{{ Statusbar --- Create a taglist widget -mytaglist = widget.new({ type = "taglist", name = "mytaglist" }) -mytaglist:mouse({}, 1, function (object, tag) awful.tag.viewonly(tag) end) -mytaglist:mouse({ modkey }, 1, function (object, tag) awful.client.toggletag(tag) end) -mytaglist:mouse({}, 3, function (object, tag) tag:view(not tag:isselected()) end) -mytaglist:mouse({ modkey }, 3, function (object, tag) awful.client.toggletag(tag) end) -mytaglist:mouse({ }, 4, awful.tag.viewnext) -mytaglist:mouse({ }, 5, awful.tag.viewprev) -mytaglist:set("text_focus", " ") +-- Create a workspacelist widget +myworkspacelist = widget.new({ type = "workspacelist", name = "myworkspacelist" }) +myworkspacelist:mouse({ }, 1, function (object, workspace) workspace:screen_set(mouse.screen_get()) end) +myworkspacelist:mouse({ }, 4, awful.workspace.viewnext) +myworkspacelist:mouse({ }, 5, awful.workspace.viewprev) +myworkspacelist:set("text_focus", "<bg color=\"#555555\"/> <title/> ") -- Create a tasklist widget 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, fg = "lightblue", bg = "black" }) -- Add widgets to the statusbar - order matters - mystatusbar:widget_add(mytaglist) + mystatusbar:widget_add(myworkspacelist) mystatusbar:widget_add(myiconbox) mystatusbar:widget_add(mytasklist) mystatusbar:widget_add(mytextbox) @@ -93,8 +85,8 @@ end -- {{{ Mouse bindings awesome.mouse({ }, 3, function () awful.spawn(terminal) end) -awesome.mouse({ }, 4, awful.tag.viewnext) -awesome.mouse({ }, 5, awful.tag.viewprev) +awesome.mouse({ }, 4, awful.workspace.viewnext) +awesome.mouse({ }, 5, awful.workspace.viewprev) client.mouse({ }, 1, function (c) c:focus_set(); c:raise() end) client.mouse({ modkey }, 1, function (c) c:mouse_move() 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 -- Compute the maximum number of digit we need, limited to 9 -keynumber = 0 -for s = 1, screen.count() do - keynumber = math.min(9, math.max(#tags[s], keynumber)); -end - +keynumber = math.min(9, #workspaces); for i = 1, keynumber do keybinding.new({ modkey }, i, function () - local screen = mouse.screen_get() - if tags[screen][i] then - awful.tag.viewonly(tags[screen][i]) - end - end):add() - keybinding.new({ modkey, "Control" }, i, - function () - local screen = mouse.screen_get() - if tags[screen][i] then - tags[i]:view(not tags[screen][i]:isselected()) - end + workspaces[i]:screen_set(mouse.screen_get()) end):add() keybinding.new({ modkey, "Shift" }, i, function () - local screen = mouse.screen_get() - if tags[screen][i] then - awful.client.movetotag(tags[screen][i]) - end - end):add() - keybinding.new({ modkey, "Control", "Shift" }, i, - function () - local screen = mouse.screen_get() - if tags[screen][i] then - awful.client.toggletag(tags[screen][i]) - end + client.focus_get():workspace_set(workspaces[i]) end):add() end -keybinding.new({ modkey }, "Left", awful.tag.viewprev):add() -keybinding.new({ modkey }, "Right", awful.tag.viewnext):add() +keybinding.new({ modkey }, "Left", awful.workspace.viewprev):add() +keybinding.new({ modkey }, "Right", awful.workspace.viewnext):add() -- Standard program 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() -- Layout manipulation -keybinding.new({ modkey }, "l", function () awful.tag.incmwfact(0.05) end):add() -keybinding.new({ modkey }, "h", function () awful.tag.incmwfact(-0.05) end):add() -keybinding.new({ modkey, "Shift" }, "h", function () awful.tag.incnmaster(1) end):add() -keybinding.new({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end):add() -keybinding.new({ modkey, "Control" }, "h", function () awful.tag.incncol(1) end):add() -keybinding.new({ modkey, "Control" }, "l", function () awful.tag.incncol(1) end):add() +keybinding.new({ modkey }, "l", function () awful.workspace.incmwfact(0.05) end):add() +keybinding.new({ modkey }, "h", function () awful.workspace.incmwfact(-0.05) end):add() +keybinding.new({ modkey, "Shift" }, "h", function () awful.workspace.incnmaster(1) end):add() +keybinding.new({ modkey, "Shift" }, "l", function () awful.workspace.incnmaster(-1) end):add() +keybinding.new({ modkey, "Control" }, "h", function () awful.workspace.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, "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. function hook_mouseover(c) -- 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() end end @@ -202,10 +170,10 @@ function hook_newclient(c) end -- Hook function to execute when arranging the screen --- (tag switch, new client, etc) -function hook_arrange(screen) - local layout = awful.layout.get(screen) - mylayoutbox[screen]:set("image", "@iconsdir@/layouts/" .. layout .. "w.png") +-- (workspace switch, new client, etc) +function hook_arrange(ws) + local screen = ws:screen_get() + mylayoutbox[screen]:set("image", "@iconsdir@/layouts/" .. ws:layout_get() .. "w.png") end -- Hook called every second diff --git a/awful.lua b/awful.lua index a512858c..ec5e0977 100644 --- a/awful.lua +++ b/awful.lua @@ -20,7 +20,7 @@ local pairs = pairs local awesome = awesome local screen = screen local client = client -local tag = tag +local workspace = workspace local mouse = mouse local os = os local table = table @@ -84,13 +84,7 @@ function client_moveresize(x, y, w, h) end function screen_focus(i) - local sel = client.focus_get() - local s - if sel then - s = sel:screen_get() - else - s = mouse.screen_get() - end + local s = mouse.screen_get() local count = screen.count() s = s + i if s < 1 then @@ -98,136 +92,81 @@ function screen_focus(i) elseif s > count then s = 1 end - screen.focus(s) + local ws = screen.workspace_get(s) + if ws then + ws:focus_set() + end -- Move the mouse on the screen local screen_coords = screen.coords_get(s) mouse.coords_set(screen_coords['x'], screen_coords['y']) 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 -function tag_setmwfact(i) - local t = tag_selected() +function workspace_setmwfact(i) + local t = workspace_selected() if t then t:mwfact_set(i) end end -- Increase master width factor -function tag_incmwfact(i) - local t = tag_selected() +function workspace_incmwfact(i) + local t = workspace_selected() if t then t:mwfact_set(t:mwfact_get() + i) end end -- Set number of master windows -function tag_setnmaster(i) - local t = tag_selected() +function workspace_setnmaster(i) + local t = workspace_selected() if t then t:nmaster_set(i) end end -- Increase number of master windows -function tag_incnmaster(i) - local t = tag_selected() +function workspace_incnmaster(i) + local t = workspace_selected() if t then t:nmaster_set(t:nmaster_get() + i) end end -- Set number of column windows -function tag_setncol(i) - local t = tag_selected() +function workspace_setncol(i) + local t = workspace_selected() if t then t:ncol_set(i) end end -- Increase number of column windows -function tag_incncol(i) - local t = tag_selected() +function workspace_incncol(i) + local t = workspace_selected() if t then t:ncol_set(t:ncol_get() + i) end end --- View no tag -function tag_viewnone() - local tags = tag.get(mouse.screen_get()) - for i, t in ipairs(tags) do - t:view(false) - end -end - -function tag_viewidx(r) - local tags = tag.get(mouse.screen_get()) - local sel = tag_selected() - tag_viewnone() - for i, t in ipairs(tags) do +function workspace_viewidx(r) + local workspaces = workspace.get() + local sel = workspace.visible_get(mouse.screen_get()) + for i, t in ipairs(workspaces) do 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 --- View next tag -function tag_viewnext() - return tag_viewidx(1) +-- View next workspace +function workspace_viewnext() + return workspace_viewidx(1) end --- View previous tag -function tag_viewprev() - return tag_viewidx(-1) -end - -function tag_viewonly(t) - tag_viewnone() - t:view(true) -end - -function tag_viewmore(tags) - tag_viewnone() - for i, t in ipairs(tags) do - t:view(true) - end -end - -function client_movetotag(target, c) - local sel = c or client.focus_get(); - local tags = tag.get(mouse.screen_get()) - for i, t in ipairs(tags) do - sel:tag(t, false) - end - sel:tag(target, true) -end - -function client_toggletag(target, c) - local sel = c or client.focus_get(); - if sel then - sel:tag(target, not sel:istagged(target)) - end +-- View previous workspace +function workspace_viewprev() + return workspace_viewidx(-1) end function client_togglefloating(c) @@ -250,18 +189,11 @@ function client_movetoscreen(c, s) end end -function layout_get(screen) - local t = tag_selected(screen) - if t then - return t:layout_get() - end -end - --- Function to change the layout of the current tag. +-- Function to change the layout of the current workspace. -- layouts = table of layouts (define in .awesomerc.lua) -- i = relative index function layout_inc(layouts, i) - local t = tag_selected() + local t = workspace.visible_get(mouse.screen_get()) local number_of_layouts = 0 local rev_layouts = {} for i, v in ipairs(layouts) do @@ -269,7 +201,7 @@ function layout_inc(layouts, i) number_of_layouts = number_of_layouts + 1 end 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 if new_layout_index == 0 then new_layout_index = number_of_layouts @@ -278,9 +210,9 @@ function layout_inc(layouts, i) 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) - local t = tag_selected() + local t = workspace.visible_get(mouse.screen_get()) if t then t:layout_set(layout) end @@ -340,30 +272,24 @@ function spawn(cmd) return os.execute(cmd .. "&") end --- Export tags function -P.tag = +-- Export workspaces function +P.workspace = { - viewnone = tag_viewnone; - viewprev = tag_viewprev; - viewnext = tag_viewnext; - viewonly = tag_viewonly; - viewmore = tag_viewmore; - setmwfact = tag_setmwfact; - incmwfact = tag_incmwfact; - setncol = tag_setncol; - incncol = tag_incncol; - setnmaster = tag_setnmaster; - incnmaster = tag_incnmaster; - selected = tag_selected; - selectedlist = tag_selectedlist; + viewprev = workspace_viewprev; + viewnext = workspace_viewnext; + setmwfact = workspace_setmwfact; + incmwfact = workspace_incmwfact; + setncol = workspace_setncol; + incncol = workspace_incncol; + setnmaster = workspace_setnmaster; + incnmaster = workspace_incnmaster; } P.client = { next = client_next; focus = client_focus; swap = client_swap; - movetotag = client_movetotag; - toggletag = client_toggletag; + movetoworkspace = client_movetoworkspace; togglefloating = client_togglefloating; moveresize = client_moveresize; movetoscreen = client_movetoscreen; @@ -374,7 +300,6 @@ P.screen = } P.layout = { - get = layout_get; set = layout_set; inc = layout_inc; } diff --git a/client.c b/client.c index 060b2d89..3c943152 100644 --- a/client.c +++ b/client.c @@ -27,7 +27,7 @@ #include <xcb/shape.h> #include "client.h" -#include "tag.h" +#include "workspace.h" #include "window.h" #include "focus.h" #include "ewmh.h" @@ -44,40 +44,40 @@ 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. - * \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 screen A virtual screen number. * \return True if client had property, false otherwise. */ static bool -client_loadprops(client_t * c, int screen) +client_loadprops(client_t * c) { - int i, ntags = 0; - tag_t *tag; + int i, nworkspaces = 0; + workspace_t *workspace; char *prop = NULL; bool result = false; + xutil_intern_atom_request_t atom_q; - for(tag = globalconf.screens[screen].tags; tag; tag = tag->next) - ntags++; + atom_q = xutil_intern_atom(globalconf.connection, &globalconf.atoms, "_AWESOME_PROPERTIES"); + + for(workspace = globalconf.workspaces; workspace; workspace = workspace->next) + nworkspaces++; if(xutil_gettextprop(globalconf.connection, c->win, &globalconf.atoms, - xutil_intern_atom_reply(globalconf.connection, &globalconf.atoms, - xutil_intern_atom(globalconf.connection, - &globalconf.atoms, - "_AWESOME_PROPERTIES")), + xutil_intern_atom_reply(globalconf.connection, &globalconf.atoms, atom_q), &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') { - tag_client(c, tag); + workspace_client_set(c, workspace); result = true; + break; } - else - untag_client(c, tag); + /* jump to the end */ + i = nworkspaces; if(prop[i]) 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); @@ -115,44 +115,42 @@ window_isprotodel(xcb_window_t win) 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. * \param c The client. - * \return True if client is tagged, false otherwise. + * \return True if client is visible, false otherwise. */ static bool client_isvisible_anyscreen(client_t *c) { - tag_t *tag; + workspace_t *ws; int screen; if(c) + { + ws = workspace_client_get(c); for(screen = 0; screen < globalconf.screens_info->nscreen; screen++) - for(tag = globalconf.screens[screen].tags; tag; tag = tag->next) - if(tag->selected && is_client_tagged(c, tag)) - return true; + if(globalconf.screens[screen].workspace == ws) + return true; + } return false; } -/** Returns true if a client is tagged - * with one of the tags of the specified screen. +/** Returns true if a client is on the workspace visible on the specified + * screen. * \param c The client to check. * \param screen Virtual screen number. - * \return true if the client is visible, false otherwise. + * \return True if the client is visible, false otherwise. */ bool client_isvisible(client_t *c, int screen) { - tag_t *tag; - - 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; - + if(c) + return (workspace_client_get(c) == globalconf.screens[screen].workspace); return false; } + /** Get a client by its window. * \param w The client window to find. * \return A client pointer if found, NULL otherwise. @@ -195,18 +193,18 @@ client_updatetitle(client_t *c) luaA_client_userdata_new(c); luaA_dofunction(globalconf.L, globalconf.hooks.titleupdate, 1); - widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); + widget_invalidate_cache(WIDGET_CACHE_CLIENTS); } static void client_unfocus(client_t *c) { /* Call hook */ - luaA_client_userdata_new(globalconf.focus->client); + luaA_client_userdata_new(c); luaA_dofunction(globalconf.L, globalconf.hooks.unfocus, 1); focus_client_push(NULL); - widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); + widget_invalidate_cache(WIDGET_CACHE_CLIENTS); } /** 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, * \param c The client or NULL. - * \param screen Virtual screen number. - * \return True if a window (even root) has received focus, false otherwise. + * \return True if a window (even root). */ bool -client_focus(client_t *c, int screen) +client_focus(client_t *c) { int phys_screen; - /* if c is NULL or invisible, take next client in the focus history */ - if((!c || (c && (!client_isvisible(c, screen)))) - && !(c = focus_get_current_client(screen))) - /* if c is still NULL take next client in the stack */ - for(c = globalconf.clients; c && (c->skip || !client_isvisible(c, screen)); c = c->next); + if(!c) + return false; /* unfocus current selected client */ if(globalconf.focus->client) client_unfocus(globalconf.focus->client); - if(c) - { - /* unban the client before focusing or it will fail */ - client_unban(c); - /* save sel in focus history */ - focus_client_push(c); - xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_POINTER_ROOT, - c->win, XCB_CURRENT_TIME); - /* since we're dropping EnterWindow events and sometimes the window - * will appear under the mouse, grabbuttons */ - window_grabbuttons(c->win, c->phys_screen); - phys_screen = c->phys_screen; + /* unban the client before focusing or it will fail */ + client_unban(c); + /* save sel in focus history */ + focus_client_push(c); + xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_POINTER_ROOT, + c->win, XCB_CURRENT_TIME); + /* since we're dropping EnterWindow events and sometimes the window + * will appear under the mouse, grabbuttons */ + window_grabbuttons(c->win, c->phys_screen); + phys_screen = c->phys_screen; - /* Some layouts use focused client differently, so call them back. */ - globalconf.screens[c->screen].need_arrange = true; + /* Some layouts use focused client differently, so call them back. */ + workspace_client_get(c)->need_arrange = true; - /* execute hook */ - luaA_client_userdata_new(globalconf.focus->client); - 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); - } + /* execute hook */ + luaA_client_userdata_new(globalconf.focus->client); + luaA_dofunction(globalconf.L, globalconf.hooks.focus, 1); ewmh_update_net_active_window(phys_screen); - widget_invalidate_cache(screen, WIDGET_CACHE_CLIENTS); + widget_invalidate_cache(WIDGET_CACHE_CLIENTS); 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; xcb_window_t trans; bool rettrans, retloadprops; - tag_t *tag; xcb_size_hints_t *u_size_hints; + int rscreen; const uint32_t select_input_val[] = { XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_ENTER_WINDOW }; 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) c->phys_screen = globalconf.default_screen; else - c->phys_screen = c->screen; + c->phys_screen = rscreen; /* Initial values */ c->win = w; @@ -358,18 +341,16 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int screen) client_updatewmhints(c); /* Try to load props if any */ - if(!(retloadprops = client_loadprops(c, screen))) - screen_client_moveto(c, screen, true); + if(!(retloadprops = client_loadprops(c))) + workspace_client_set(c, globalconf.screens[screen].workspace); /* Then check clients hints */ 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)) && (t = client_getbywin(trans))) - for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next) - if(is_client_tagged(t, tag)) - tag_client(c, tag); + workspace_client_set(c, workspace_client_get(t)); /* should be floating if transsient or fixed */ 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 */ 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); /* update window title */ @@ -474,15 +455,16 @@ client_geometry_hints(client_t *c, area_t geometry) bool client_resize(client_t *c, area_t geometry, bool hints) { - int new_screen; - area_t area; - layout_t *layout = layout_get_current(c->screen); + int screen, new_screen; + workspace_t *ws; bool resized = false; /* Values to configure a window is an array where values are * stored according to 'value_mask' */ 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); 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) 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 || c->geometry.width != geometry.width || c->geometry.height != geometry.height) { + screen = workspace_screen_get(ws); 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.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 * maximized */ if(c->ismoving || c->isfloating - || layout_get_current(new_screen) == layout_floating) + || ws->layout == layout_floating) { titlebar_update_geometry_floating(c); if(!c->ismax) @@ -536,15 +506,12 @@ client_resize(client_t *c, area_t geometry, bool hints) values); window_configure(c->win, geometry, c->border); - if(c->screen != new_screen) - screen_client_moveto(c, new_screen, false); - resized = true; } /* call it again like it was floating, * 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); return resized; @@ -567,9 +534,8 @@ client_setfloating(client_t *c, bool floating, layer_t layer) c->ismax = false; client_resize(c, c->m_geometry, false); } - if(client_isvisible(c, c->screen)) - globalconf.screens[c->screen].need_arrange = true; - widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); + workspace_client_get(c)->need_arrange = true; + widget_invalidate_cache(WIDGET_CACHE_CLIENTS); if(floating) { c->oldlayer = c->layer; @@ -588,20 +554,23 @@ client_setfloating(client_t *c, bool floating, layer_t layer) void client_saveprops(client_t *c) { - int i = 0, ntags = 0; + int i = 0, nws = 0; char *prop; - tag_t *tag; + workspace_t *workspace, *cws = workspace_client_get(c); xutil_intern_atom_request_t atom_q; atom_q = xutil_intern_atom(globalconf.connection, &globalconf.atoms, "_AWESOME_PROPERTIES"); - for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next) - ntags++; + for(workspace = globalconf.workspaces; workspace; workspace = workspace->next) + 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++) - prop[i] = is_client_tagged(c, tag) ? '1' : '0'; + for(workspace = globalconf.workspaces; workspace; workspace = workspace->next, i++) + if(cws == workspace) + prop[i] = '1'; + else + prop[i] = '0'; prop[i] = c->isfloating ? '1' : '0'; @@ -628,8 +597,6 @@ client_unban(client_t *c) void client_unmanage(client_t *c) { - tag_t *tag; - /* The server grab construct avoids race conditions. */ xcb_grab_server(globalconf.connection); @@ -641,11 +608,11 @@ client_unmanage(client_t *c) client_list_detach(&globalconf.clients, c); focus_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) - 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); window_setstate(c->win, XCB_WM_WITHDRAWN_STATE); @@ -680,7 +647,7 @@ client_updatewmhints(client_t *c) luaA_client_userdata_new(c); 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) && (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; xcb_configure_window(globalconf.connection, c->win, 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. @@ -941,64 +908,28 @@ luaA_client_border_set(lua_State *L) return 0; } -/** Move the client to another screen. - * \param A screen number. +/** Set the client on the specified workspace. + * \param A workspace object. */ static int -luaA_client_screen_set(lua_State *L) +luaA_client_workspace_set(lua_State *L) { client_t **c = luaA_checkudata(L, 1, "client"); - int screen = luaL_checknumber(L, 2) - 1; - luaA_checkscreen(screen); - screen_client_moveto(*c, screen, true); + workspace_t **workspace = luaA_checkudata(L, 2, "workspace"); + /* arrange old ws */ + workspace_client_get(*c)->need_arrange = true; + workspace_client_set(*c, *workspace); return 0; } -/** Get the screen number the client is onto. - * \return A screen number. +/** Get the workspace the client is on. + * \return A workspace. */ static int -luaA_client_screen_get(lua_State *L) +luaA_client_workspace_get(lua_State *L) { client_t **c = luaA_checkudata(L, 1, "client"); - lua_pushnumber(L, 1 + (*c)->screen); - return 1; -} - -/** Tag a client with a specified tag. - * \param A tag object. - * \param A boolean value: true to add this tag to clients, false to remove. - */ -static int -luaA_client_tag(lua_State *L) -{ - client_t **c = luaA_checkudata(L, 1, "client"); - tag_t **tag = luaA_checkudata(L, 2, "tag"); - bool tag_the_client = luaA_checkboolean(L, 3); - - if((*tag)->screen != (*c)->screen) - luaL_error(L, "tag and client are on different screens"); - - if(tag_the_client) - tag_client(*c, *tag); - else - untag_client(*c, *tag); - - return 0; -} - -/** Check if a client is tagged with the specified tag. - * \param A tag object. - * \return A boolean value, true if the client is tagged with this tag, false - * otherwise. - */ -static int -luaA_client_istagged(lua_State *L) -{ - client_t **c = luaA_checkudata(L, 1, "client"); - tag_t **tag = luaA_checkudata(L, 2, "tag"); - lua_pushboolean(L, is_client_tagged(*c, *tag)); - return 1; + return luaA_workspace_userdata_new(workspace_client_get(*c)); } /** 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"); 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); 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 **swap = luaA_checkudata(L, 2, "client"); client_list_swap(&globalconf.clients, *swap, *c); - globalconf.screens[(*c)->screen].need_arrange = true; - globalconf.screens[(*swap)->screen].need_arrange = true; - widget_invalidate_cache((*c)->screen, WIDGET_CACHE_CLIENTS); - widget_invalidate_cache((*swap)->screen, WIDGET_CACHE_CLIENTS); + workspace_client_get(*c)->need_arrange = true; + workspace_client_get(*swap)->need_arrange = true; + widget_invalidate_cache(WIDGET_CACHE_CLIENTS); return 0; } @@ -1075,7 +1005,7 @@ static int luaA_client_focus_set(lua_State *L) { client_t **c = luaA_checkudata(L, 1, "client"); - client_focus(*c, (*c)->screen); + client_focus(*c); return 0; } @@ -1191,6 +1121,7 @@ luaA_client_titlebar_set(lua_State *L) { client_t **c = luaA_checkudata(L, 1, "client"); titlebar_t **t = luaA_checkudata(L, 2, "titlebar"); + workspace_t *ws; if(client_getbytitlebar(*t)) 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_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); else - globalconf.screens[(*c)->screen].need_arrange = true; + ws->need_arrange = true; return 0; } @@ -1258,11 +1191,9 @@ const struct luaL_reg awesome_client_meta[] = { "titlebar_get", luaA_client_titlebar_get }, { "name_get", luaA_client_name_get }, { "name_set", luaA_client_name_set }, - { "screen_set", luaA_client_screen_set }, - { "screen_get", luaA_client_screen_get }, { "border_set", luaA_client_border_set }, - { "tag", luaA_client_tag }, - { "istagged", luaA_client_istagged }, + { "workspace_set", luaA_client_workspace_set }, + { "workspace_get", luaA_client_workspace_get }, { "coords_get", luaA_client_coords_get }, { "coords_set", luaA_client_coords_set }, { "opacity_set", luaA_client_opacity_set }, diff --git a/client.h b/client.h index 108e1a3d..29e36240 100644 --- a/client.h +++ b/client.h @@ -28,7 +28,7 @@ bool client_isvisible(client_t *, int); 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_ban(client_t *); void client_unban(client_t *); diff --git a/event.c b/event.c index fa72c998..c25ba163 100644 --- a/event.c +++ b/event.c @@ -25,7 +25,6 @@ #include "screen.h" #include "event.h" -#include "tag.h" #include "statusbar.h" #include "window.h" #include "mouse.h" @@ -34,6 +33,7 @@ #include "widget.h" #include "titlebar.h" #include "lua.h" +#include "workspace.h" #include "layouts/tile.h" #include "layouts/floating.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 && 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); return 0; } @@ -181,9 +181,12 @@ event_handle_configurerequest(void *data __attribute__ ((unused)), { client_t *c; area_t geometry; + workspace_t *ws; if((c = client_getbywin(ev->window))) { + ws = workspace_client_get(c); + geometry = c->geometry; 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 || 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); 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 * has its new configuration. That fixes at least * gnome-terminal */ @@ -463,6 +466,7 @@ event_handle_propertynotify(void *data __attribute__ ((unused)), { client_t *c; xcb_window_t trans; + workspace_t *ws; if(ev->state == XCB_PROPERTY_DELETE) return 0; /* ignore */ @@ -470,10 +474,11 @@ event_handle_propertynotify(void *data __attribute__ ((unused)), { if(ev->atom == WM_TRANSIENT_FOR) { + ws = workspace_client_get(c); xutil_get_transient_for_hint(connection, c->win, &trans); if(!c->isfloating && (c->isfloating = (client_getbywin(trans) != NULL))) - globalconf.screens[c->screen].need_arrange = true; + ws->need_arrange = true; } else if (ev->atom == WM_NORMAL_HINTS) client_updatesizehints(c); diff --git a/ewmh.c b/ewmh.c index 596df8f2..cce86e25 100644 --- a/ewmh.c +++ b/ewmh.c @@ -24,7 +24,7 @@ #include <xcb/xcb_aux.h> #include "ewmh.h" -#include "tag.h" +#include "workspace.h" #include "focus.h" #include "screen.h" #include "client.h" @@ -188,9 +188,9 @@ void ewmh_update_net_numbers_of_desktop(int phys_screen) { 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++; xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, @@ -202,16 +202,14 @@ void ewmh_update_net_current_desktop(int phys_screen) { 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++; xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, xcb_aux_get_screen(globalconf.connection, phys_screen)->root, net_current_desktop, CARDINAL, 32, 1, &count); - - p_delete(&curtags); } void @@ -219,14 +217,14 @@ ewmh_update_net_desktop_names(int phys_screen) { char buf[1024], *pos; ssize_t len, curr_size; - tag_t *tag; + workspace_t *workspace; pos = buf; 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); - a_strcpy(pos, sizeof(buf), tag->name); + curr_size = a_strlen(workspace->name); + a_strcpy(pos, sizeof(buf), workspace->name); pos += curr_size + 1; len += curr_size + 1; } @@ -240,7 +238,7 @@ void ewmh_update_net_active_window(int phys_screen) { 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; @@ -253,12 +251,11 @@ static void ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set) { const uint32_t raise_window_val = XCB_STACK_MODE_ABOVE; + int screen; if(state == net_wm_state_sticky) { - tag_t *tag; - for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next) - tag_client(c, tag); + /* \todo support for sticky */ } 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) { - 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 */ c->m_geometry = c->geometry; c->wasfloating = c->isfloating; @@ -306,7 +304,7 @@ ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set) c->noborder = true; 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); 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; int screen; + unsigned int i; + workspace_t *ws; if(ev->type == net_current_desktop) + { for(screen = 0; screen < xcb_setup_roots_length(xcb_get_setup(globalconf.connection)); screen++) - { if(ev->window == xcb_aux_get_screen(globalconf.connection, screen)->root) - tag_view_only_byindex(screen, ev->data.data32[0]); - } - - if(ev->type == net_close_window) + { + for(i = 0, ws = globalconf.workspaces; i < ev->data.data32[0]; i++, ws = ws ->next); + globalconf.screens[screen].workspace = ws; + } + } + else if(ev->type == net_close_window) { if((c = client_getbywin(ev->window))) client_kill(c); diff --git a/focus.c b/focus.c index 05a073a5..e1df6a49 100644 --- a/focus.c +++ b/focus.c @@ -21,7 +21,7 @@ #include "focus.h" #include "cnode.h" -#include "tag.h" +#include "workspace.h" extern awesome_t globalconf; @@ -61,38 +61,28 @@ focus_client_delete(client_t *c) } 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; - tag_t **tags; int i = 0; for(node = globalconf.focus; node; node = node->next) if(node->client && !node->client->skip) - for(tags = t; *tags; tags++) - if(is_client_tagged(node->client, *tags)) - { - if(i == nindex) - return node->client; - else - i--; - } + if(workspace_client_get(node->client) == ws) + if(i-- == nindex) + return node->client; return NULL; } -/** Get the latest focused client on a screen. - * \param screen The virtual screen number. +/** Get the latest focused client on a workspace. + * \param ws The workspace. * \return A pointer to an existing client. */ client_t * -focus_get_current_client(int screen) +focus_client_getcurrent(workspace_t *ws) { - tag_t **curtags = tags_get_current(screen); - client_t *sel = focus_get_latest_client_for_tags(curtags, 0); - p_delete(&curtags); - - return sel; + return focus_get_latest_client_for_workspace(ws, 0); } // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/focus.h b/focus.h index 2662d16d..b233b629 100644 --- a/focus.h +++ b/focus.h @@ -27,7 +27,7 @@ void focus_client_push(client_t *); void focus_client_append(client_t *); void focus_client_delete(client_t *); -client_t * focus_get_current_client(int); +client_t * focus_client_getcurrent(workspace_t *); #endif // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/layout.c b/layout.c index b513c90b..ed6c3112 100644 --- a/layout.c +++ b/layout.c @@ -23,13 +23,12 @@ #include <xcb/xcb_atom.h> #include <xcb/xcb_aux.h> -#include "tag.h" #include "focus.h" #include "widget.h" #include "window.h" #include "client.h" #include "screen.h" -#include "layouts/magnifier.h" +#include "workspace.h" #include "layouts/tile.h" #include "layouts/max.h" #include "layouts/fibonacci.h" @@ -37,26 +36,27 @@ extern awesome_t globalconf; -/** Arrange windows following current selected layout - * \param screen the screen to arrange +/** Arrange windows following current selected layout. + * \param ws The workspace to arrange. */ static void -arrange(int screen) +arrange(workspace_t *ws) { client_t *c; - layout_t *curlay = layout_get_current(screen); - int fscreen, phys_screen = screen_virttophys(screen); + int fscreen, screen = workspace_screen_get(ws), phys_screen = screen_virttophys(screen); xcb_query_pointer_cookie_t qp_c; xcb_query_pointer_reply_t *qp_r; + workspace_t *cws; for(c = globalconf.clients; c; c = c->next) - { - if(client_isvisible(c, screen)) + if((cws = workspace_client_get(c)) == ws) + { + screen_client_moveto(c, screen); client_unban(c); + } /* we don't touch other screens windows */ - else if(c->screen == screen) + else if(workspace_screen_get(cws) == -1) client_ban(c); - } qp_c = xcb_query_pointer_unchecked(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 * client are currently focused, pick the first one in history */ if(fscreen == screen - && (c = focus_get_current_client(screen))) - client_focus(c, screen); + && (c = focus_client_getcurrent(ws))) + client_focus(c); } p_delete(&qp_r); } - if(curlay) - curlay(screen); + if(ws->layout) + ws->layout(ws); /* reset status */ - globalconf.screens[screen].need_arrange = false; + ws->need_arrange = false; /* call hook */ - lua_pushnumber(globalconf.L, screen + 1); + luaA_workspace_userdata_new(ws); luaA_dofunction(globalconf.L, globalconf.hooks.arrange, 1); } -/** Refresh the screen disposition - * \return true if the screen was arranged, false otherwise +/** Refresh the screens disposition. */ void layout_refresh(void) @@ -108,25 +107,8 @@ layout_refresh(void) int screen; for(screen = 0; screen < globalconf.screens_info->nscreen; screen++) - if(globalconf.screens[screen].need_arrange) - arrange(screen); -} - -/** Get current layout used on screen. - * \param screen Virtual screen number. - * \return layout used on that screen - */ -layout_t * -layout_get_current(int screen) -{ - layout_t *l = NULL; - tag_t **curtags = tags_get_current(screen); - - if(curtags[0]) - l = curtags[0]->layout; - p_delete(&curtags); - - return l; + if(globalconf.screens[screen].workspace && globalconf.screens[screen].workspace->need_arrange) + arrange(globalconf.screens[screen].workspace); } // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/layout.h b/layout.h index 2ceffb45..61612623 100644 --- a/layout.h +++ b/layout.h @@ -25,9 +25,6 @@ #include "common/list.h" #include "common/util.h" -typedef void (layout_t)(int); - -layout_t * layout_get_current(int); void layout_refresh(void); #endif diff --git a/layouts/fibonacci.c b/layouts/fibonacci.c index 6b3b2c76..04f311d7 100644 --- a/layouts/fibonacci.c +++ b/layouts/fibonacci.c @@ -20,18 +20,19 @@ */ #include "screen.h" -#include "tag.h" +#include "workspace.h" #include "client.h" #include "layouts/fibonacci.h" extern awesome_t globalconf; static void -layout_fibonacci(int screen, int shape) +layout_fibonacci(workspace_t *ws, int shape) { int n = 0, i = 0; client_t *c; area_t geometry, area; + int screen = workspace_screen_get(ws); geometry = area = screen_area_get(screen, globalconf.screens[screen].statusbar, &globalconf.screens[screen].padding); @@ -88,15 +89,15 @@ layout_fibonacci(int screen, int shape) } void -layout_spiral(int screen) +layout_spiral(workspace_t *ws) { - layout_fibonacci(screen, 0); + layout_fibonacci(ws, 0); } 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 diff --git a/layouts/floating.c b/layouts/floating.c index 678149bd..13b6eda8 100644 --- a/layouts/floating.c +++ b/layouts/floating.c @@ -20,15 +20,16 @@ */ #include "client.h" -#include "tag.h" +#include "workspace.h" #include "layouts/floating.h" extern awesome_t globalconf; void -layout_floating(int screen) +layout_floating(workspace_t *ws) { client_t *c; + int screen = workspace_screen_get(ws); for(c = globalconf.clients; c; c = c->next) if(client_isvisible(c, screen) && !c->ismax) diff --git a/layouts/magnifier.c b/layouts/magnifier.c index f76e3851..8e20f0c3 100644 --- a/layouts/magnifier.c +++ b/layouts/magnifier.c @@ -20,7 +20,7 @@ */ #include "client.h" -#include "tag.h" +#include "workspace.h" #include "screen.h" #include "focus.h" #include "layouts/magnifier.h" @@ -28,16 +28,16 @@ extern awesome_t globalconf; void -layout_magnifier(int screen) +layout_magnifier(workspace_t *ws) { int n = 0; 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, globalconf.screens[screen].statusbar, &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(!IS_TILED(focus, screen)) @@ -45,10 +45,10 @@ layout_magnifier(int screen) /* No windows is tiled, nothing to do. */ if(!focus) - goto bailout; + return; - geometry.width = area.width * curtags[0]->mwfact; - geometry.height = area.height * curtags[0]->mwfact; + geometry.width = area.width * ws->mwfact; + geometry.height = area.height * ws->mwfact; geometry.x = area.x + (area.width - geometry.width) / 2; geometry.y = area.y + (area.height - geometry.height) / 2; client_resize(focus, geometry, globalconf.resize_hints); @@ -62,7 +62,7 @@ layout_magnifier(int screen) /* No other clients. */ if(!n) - goto bailout; + return; geometry.x = area.x; geometry.y = area.y; @@ -81,8 +81,5 @@ layout_magnifier(int screen) geometry.width += 2 * c->border; geometry.y += geometry.height; } - -bailout: - p_delete(&curtags); } // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/layouts/max.c b/layouts/max.c index fd71f930..e348196c 100644 --- a/layouts/max.c +++ b/layouts/max.c @@ -19,7 +19,7 @@ * */ -#include "tag.h" +#include "workspace.h" #include "screen.h" #include "client.h" #include "focus.h" @@ -28,12 +28,13 @@ extern awesome_t globalconf; void -layout_max(int screen) +layout_max(workspace_t *ws) { client_t *c, *focus; + int screen = workspace_screen_get(ws); area_t area = screen_area_get(screen, - globalconf.screens[screen].statusbar, - &globalconf.screens[screen].padding); + globalconf.screens[screen].statusbar, + &globalconf.screens[screen].padding); for(c = globalconf.clients; c; c = c->next) if(IS_TILED(c, screen)) @@ -45,7 +46,7 @@ layout_max(int screen) area.height += 2 * c->border; } - if((focus = focus_get_current_client(screen)) + if((focus = focus_client_getcurrent(screen)) && IS_TILED(focus, screen)) client_raise(focus); } diff --git a/layouts/tile.c b/layouts/tile.c index c15771ad..342ee001 100644 --- a/layouts/tile.c +++ b/layouts/tile.c @@ -22,7 +22,7 @@ #include <stdio.h> #include "screen.h" -#include "tag.h" +#include "workspace.h" #include "client.h" #include "layouts/tile.h" #include "common/util.h" @@ -30,17 +30,18 @@ extern awesome_t globalconf; static void -_tile(int screen, const position_t position) +_tile(workspace_t *ws, const position_t position) { /* windows area geometry */ int wah = 0, waw = 0, wax = 0, way = 0; /* master size */ unsigned int mw = 0, mh = 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 }; client_t *c; - tag_t **curtags = tags_get_current(screen); + + screen = workspace_screen_get(ws); area = screen_area_get(screen, globalconf.screens[screen].statusbar, @@ -55,34 +56,34 @@ _tile(int screen, const position_t position) wax = area.x; way = area.y; - masterwin = MIN(n, curtags[0]->nmaster); + masterwin = MIN(n, ws->nmaster); otherwin = MAX(n - masterwin, 0); - if(curtags[0]->nmaster) + if(ws->nmaster) switch(position) { case Right: case Left: mh = masterwin ? wah / masterwin : wah; - mw = otherwin ? waw * curtags[0]->mwfact : waw; + mw = otherwin ? waw * ws->mwfact : waw; break; default: - mh = otherwin ? wah * curtags[0]->mwfact : wah; + mh = otherwin ? wah * ws->mwfact : wah; mw = masterwin ? waw / masterwin : waw; break; } else 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) { if(!IS_TILED(c, screen)) continue; - if(i < curtags[0]->nmaster) + if(i < ws->nmaster) { switch(position) { @@ -116,8 +117,8 @@ _tile(int screen, const position_t position) if(real_ncol) win_by_col = otherwin / real_ncol; - if((i - curtags[0]->nmaster) - && (i - curtags[0]->nmaster) % win_by_col == 0 + if((i - ws->nmaster) + && (i - ws->nmaster) % win_by_col == 0 && current_col < real_ncol - 1) current_col++; @@ -133,10 +134,10 @@ _tile(int screen, const position_t position) 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; 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); @@ -152,10 +153,10 @@ _tile(int screen, const position_t position) 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; 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); @@ -166,32 +167,30 @@ _tile(int screen, const position_t position) } i++; } - - p_delete(&curtags); } void -layout_tile(int screen) +layout_tile(workspace_t *ws) { - _tile(screen, Right); + _tile(ws, Right); } void -layout_tileleft(int screen) +layout_tileleft(workspace_t *ws) { - _tile(screen, Left); + _tile(ws, Left); } void -layout_tilebottom(int screen) +layout_tilebottom(workspace_t *ws) { - _tile(screen, Bottom); + _tile(ws, Bottom); } 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 diff --git a/lua.c b/lua.c index 65ab2d88..389ef06d 100644 --- a/lua.c +++ b/lua.c @@ -32,7 +32,7 @@ #include "config.h" #include "structs.h" #include "lua.h" -#include "tag.h" +#include "workspace.h" #include "client.h" #include "window.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_titlebar_methods[]; extern const struct luaL_reg awesome_titlebar_meta[]; -extern const struct luaL_reg awesome_tag_methods[]; -extern const struct luaL_reg awesome_tag_meta[]; +extern const struct luaL_reg awesome_workspace_methods[]; +extern const struct luaL_reg awesome_workspace_meta[]; extern const struct luaL_reg awesome_widget_methods[]; extern const struct luaL_reg awesome_widget_meta[]; extern const struct luaL_reg awesome_statusbar_methods[]; @@ -191,16 +191,17 @@ luaA_screen_count(lua_State *L) return 1; } -/** Give the focus to a screen. - * \param A screen number - */ +/** Get the workspace displayed on a screen. + * \param A screen number. +*/ static int -luaA_screen_focus(lua_State *L) +luaA_screen_workspace_get(lua_State *L) { /* Our table begin at 0, Lua begins at 1 */ int screen = luaL_checknumber(L, 1) - 1; luaA_checkscreen(screen); - client_focus(NULL, screen); + if(globalconf.screens[screen].workspace) + return luaA_workspace_userdata_new(globalconf.screens[screen].workspace); return 0; } @@ -426,7 +427,7 @@ luaA_init(void) { { "coords_get", luaA_screen_coords_get }, { "count", luaA_screen_count }, - { "focus", luaA_screen_focus }, + { "workspace_get", luaA_screen_workspace_get }, { NULL, NULL } }; static const struct luaL_reg awesome_hooks_lib[] = @@ -458,8 +459,8 @@ luaA_init(void) /* Export hooks lib */ luaL_register(L, "mouse", awesome_mouse_lib); - /* Export tag */ - luaA_openlib(L, "tag", awesome_tag_methods, awesome_tag_meta); + /* Export workspace */ + luaA_openlib(L, "workspace", awesome_workspace_methods, awesome_workspace_meta); /* Export statusbar */ luaA_openlib(L, "statusbar", awesome_statusbar_methods, awesome_statusbar_meta); @@ -491,18 +492,13 @@ luaA_init(void) bool luaA_parserc(const char* rcfile) { - int screen; - if(luaL_dofile(globalconf.L, rcfile)) { fprintf(stderr, "%s\n", lua_tostring(globalconf.L, -1)); return false; } - /* Assure there's at least one tag */ - for(screen = 0; screen < globalconf.screens_info->nscreen; screen++) - if(!globalconf.screens[screen].tags) - tag_append_to_screen(tag_new("default", layout_tile, 0.5, 1, 0), screen); + /* \todo Assure there's at least one workspace */ return true; } diff --git a/mouse.c b/mouse.c index 4d83ccfa..e13d4d6c 100644 --- a/mouse.c +++ b/mouse.c @@ -27,7 +27,7 @@ #include "mouse.h" #include "screen.h" -#include "tag.h" +#include "workspace.h" #include "event.h" #include "client.h" #include "titlebar.h" @@ -126,11 +126,12 @@ static area_t mouse_snapclient(client_t *c, area_t geometry, int snap) { client_t *snapper; + int screen = workspace_screen_get(workspace_client_get(c)); area_t snapper_geometry; area_t screen_geometry = - screen_area_get(c->screen, - globalconf.screens[c->screen].statusbar, - &globalconf.screens[c->screen].padding); + screen_area_get(screen, + globalconf.screens[screen].statusbar, + &globalconf.screens[screen].padding); geometry = titlebar_geometry_add(c->titlebar, geometry); 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); 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.width += 2 * c->border; @@ -296,10 +297,9 @@ mouse_warp_pointer(xcb_window_t window, int x, int y) static void mouse_client_move(client_t *c, int snap) { - int ocx, ocy, newscreen; area_t geometry; client_t *target; - layout_t *layout; + workspace_t *ws = workspace_client_get(c); simple_window_t *sw = NULL; draw_context_t *ctx; 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_cookie_t query_pointer_c; 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); /* 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); - 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); xcb_aux_sync(globalconf.connection); } while(true) - { /* XMaskEvent allows to retrieve only specified events from * the queue and requeue the other events... */ while(ev || (ev = xcb_wait_for_event(globalconf.connection))) - { switch((ev->response_type & 0x7f)) { case XCB_BUTTON_RELEASE: @@ -359,7 +357,7 @@ mouse_client_move(client_t *c, int snap) p_delete(&ev); return; 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; @@ -380,20 +378,24 @@ mouse_client_move(client_t *c, int snap) { query_pointer_c = xcb_query_pointer_unchecked(globalconf.connection, s->root); 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_y)) != c->screen) + mquery_pointer_r->root_y)) != screen + && globalconf.screens[newscreen].workspace) { - screen_client_moveto(c, newscreen, true); - globalconf.screens[c->screen].need_arrange = true; - globalconf.screens[newscreen].need_arrange = true; + ws->need_arrange = true; + ws = globalconf.screens[newscreen].workspace; + screen = workspace_screen_get(ws); + workspace_client_set(c, ws); + ws->need_arrange = true; layout_refresh(); } if((target = client_getbywin(mquery_pointer_r->child)) && target != c && !target->isfloating) { client_list_swap(&globalconf.clients, c, target); - globalconf.screens[c->screen].need_arrange = true; + ws->need_arrange = true; layout_refresh(); } p_delete(&mquery_pointer_r); @@ -408,8 +410,6 @@ mouse_client_move(client_t *c, int snap) p_delete(&ev); break; } - } - } } @@ -577,62 +577,57 @@ mouse_client_resize_floating(client_t *c, corner_t corner) } /** 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 mouse_client_resize_tiled(client_t *c) { - xcb_screen_t *screen; + xcb_screen_t *xscreen; /* screen area modulo statusbar */ area_t area; - /* current tag */ - tag_t *tag; - /* current layout */ - layout_t *layout; - - int mouse_x, mouse_y; + /* current workspace */ + workspace_t *ws = workspace_client_get(c); + int mouse_x, mouse_y, screen = workspace_screen_get(ws); size_t cursor = CurResize; - screen = xcb_aux_get_screen(globalconf.connection, c->phys_screen); - tag = tags_get_current(c->screen)[0]; - layout = tag->layout; + xscreen = xcb_aux_get_screen(globalconf.connection, c->phys_screen); - area = screen_area_get(tag->screen, - globalconf.screens[tag->screen].statusbar, - &globalconf.screens[tag->screen].padding); + area = screen_area_get(screen, + globalconf.screens[screen].statusbar, + &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 */ - 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; } - 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; } - 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; } - 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; } else return; /* grab the pointer */ - if(!mouse_grab_pointer(screen->root, cursor)) + if(!mouse_grab_pointer(xscreen->root, cursor)) return; /* 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); @@ -645,20 +640,20 @@ mouse_client_resize_tiled(client_t *c) fact_x = (double) (mouse_x - area.x) / area.width; fact_y = (double) (mouse_y - area.y) / area.height; - if(layout == layout_tile) + if(ws->layout == layout_tile) mwfact = fact_x; - else if(layout == layout_tileleft) + else if(ws->layout == layout_tileleft) mwfact = 1. - fact_x; - else if(layout == layout_tilebottom) + else if(ws->layout == layout_tilebottom) mwfact = fact_y; - else if(layout == layout_tiletop) + else if(ws->layout == layout_tiletop) mwfact = 1. - fact_y; /* refresh layout */ - if(fabs(tag->mwfact - mwfact) >= 0.01) + if(fabs(ws->mwfact - mwfact) >= 0.01) { - tag->mwfact = mwfact; - globalconf.screens[tag->screen].need_arrange = true; + ws->mwfact = mwfact; + ws->need_arrange = true; layout_refresh(); xcb_aux_sync(globalconf.connection); } @@ -679,16 +674,13 @@ static void mouse_client_resize(client_t *c, corner_t corner) { int n, screen; - tag_t **curtags; - layout_t *layout; + workspace_t *ws = workspace_client_get(c); xcb_screen_t *s; - curtags = tags_get_current(c->screen); - layout = curtags[0]->layout; s = xcb_aux_get_screen(globalconf.connection, c->phys_screen); /* only handle floating and tiled layouts */ - if(layout == layout_floating || c->isfloating) + if(ws->layout == layout_floating || c->isfloating) { if(c->isfixed) return; @@ -697,16 +689,16 @@ mouse_client_resize(client_t *c, corner_t corner) mouse_client_resize_floating(c, corner); } - else if (layout == layout_tile || layout == layout_tileleft - || layout == layout_tilebottom || layout == layout_tiletop) + else if (ws->layout == layout_tile || ws->layout == layout_tileleft + || 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) if(IS_TILED(c, screen)) n++; /* only masters on this screen? */ - if(n <= curtags[0]->nmaster) return; + if(n <= ws->nmaster) return; /* no tiled clients on this screen? */ for(c = globalconf.clients; c && !IS_TILED(c, screen); c = c->next); diff --git a/placement.c b/placement.c index 5ee5c843..0a40973a 100644 --- a/placement.c +++ b/placement.c @@ -26,6 +26,7 @@ #include "screen.h" #include "client.h" #include "titlebar.h" +#include "workspace.h" #include "layouts/floating.h" extern awesome_t globalconf; @@ -71,21 +72,21 @@ placement_smart(client_t *c) area_t newgeometry = { 0, 0, 0, 0, NULL, NULL }; area_t *screen_geometry, *arealist = NULL, *r; 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 = screen_area_get(c->screen, - globalconf.screens[c->screen].statusbar, - &globalconf.screens[c->screen].padding); + *screen_geometry = screen_area_get(screen, + globalconf.screens[screen].statusbar, + &globalconf.screens[screen].padding); - layout = layout_get_current(c->screen); area_list_push(&arealist, screen_geometry); for(client = globalconf.clients; client; client = client->next) - if((client->isfloating || layout == layout_floating) - && client_isvisible(client, c->screen)) + if((client->isfloating || ws->layout == layout_floating) + && client_isvisible(client, screen)) { newgeometry = client->f_geometry; newgeometry.width += 2 * client->border; @@ -119,7 +120,7 @@ placement_smart(client_t *c) newgeometry.height = c->f_geometry.height; 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); area_list_wipe(&arealist); @@ -133,6 +134,7 @@ placement_under_mouse(client_t *c) xcb_query_pointer_cookie_t qp_c; xcb_query_pointer_reply_t *qp_r; area_t finalgeometry = c->f_geometry; + int screen = workspace_screen_get(workspace_client_get(c)); qp_c = xcb_query_pointer(globalconf.connection, 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 = placement_fix_offscreen(finalgeometry, c->screen, c->border); + finalgeometry = placement_fix_offscreen(finalgeometry, screen, c->border); finalgeometry = titlebar_geometry_remove(c->titlebar, finalgeometry); return finalgeometry; diff --git a/screen.c b/screen.c index dbec291b..a2a57031 100644 --- a/screen.c +++ b/screen.c @@ -25,9 +25,9 @@ #include <xcb/xcb_aux.h> #include "screen.h" -#include "tag.h" #include "focus.h" #include "client.h" +#include "workspace.h" #include "layouts/floating.h" extern awesome_t globalconf; @@ -121,93 +121,80 @@ screen_virttophys(int screen) /** Move a client to a virtual screen. * \param c The client to move. - * \param new_screen The destinatiuon screen number. - * \param doresize Set to true if we also move the client to the new x and - * y of the new screen. + * \param new_screen The new screen. */ void -screen_client_moveto(client_t *c, int new_screen, bool doresize) +screen_client_moveto(client_t *c, int new_screen) { - tag_t *tag; - int old_screen = c->screen; - area_t from, to; + area_t from, to, new_geometry, new_f_geometry; + int old_screen; - for(tag = globalconf.screens[old_screen].tags; tag; tag = tag->next) - untag_client(c, tag); + old_screen = screen_get_bycoord(globalconf.screens_info, c->phys_screen, + 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 */ - tag_client_with_current_selected(c); + new_f_geometry = c->f_geometry; - /* resize the windows if it's floating */ - if(doresize && old_screen != c->screen) + from = screen_area_get(old_screen, NULL, NULL); + 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_f_geometry = c->f_geometry; - - to = screen_area_get(c->screen, NULL, NULL); - from = screen_area_get(old_screen, NULL, NULL); + new_geometry = c->geometry; /* 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; + new_geometry.x = (c->geometry.x - from.x) + to.x; + new_geometry.y = (c->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(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; - if(c->ismax) - { - new_geometry = c->geometry; + /* 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; - /* compute new coords in new screen */ - new_geometry.x = (c->geometry.x - from.x) + to.x; - new_geometry.y = (c->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; - /* check that new coords are still in the screen */ - 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; - } + 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; } // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/screen.h b/screen.h index ff132db9..71dc8f45 100644 --- a/screen.h +++ b/screen.h @@ -27,7 +27,7 @@ area_t screen_area_get(int, statusbar_t *, padding_t *); area_t display_area_get(int, statusbar_t *, padding_t *); int screen_virttophys(int); -void screen_client_moveto(client_t *, int, bool); +void screen_client_moveto(client_t *, int); #endif // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/statusbar.c b/statusbar.c index dcafed3e..e99b3db2 100644 --- a/statusbar.c +++ b/statusbar.c @@ -24,7 +24,6 @@ #include "statusbar.h" #include "screen.h" -#include "tag.h" #include "widget.h" #include "window.h" @@ -80,7 +79,8 @@ statusbar_position_update(statusbar_t *statusbar, position_t position) xcb_screen_t *s = NULL; 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); draw_context_delete(&statusbar->ctx); @@ -412,7 +412,8 @@ luaA_statusbar_remove(lua_State *L) statusbar_position_update(*sb, Off); statusbar_list_detach(&globalconf.screens[i].statusbar, *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; } diff --git a/structs.h b/structs.h index 034b034d..fd947f6e 100644 --- a/structs.h +++ b/structs.h @@ -50,6 +50,8 @@ enum 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 widget_t widget_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 keybinding_t keybinding_t; typedef struct client_node_t client_node_t; -typedef struct _tag_t tag_t; -typedef struct tag_client_node_t tag_client_node_t; +typedef struct workspace_client_node_t workspace_client_node_t; typedef area_t (FloatingPlacement)(client_t *); typedef struct awesome_t awesome_t; @@ -279,8 +280,6 @@ struct client_t client_t *prev, *next; /** Window of the client */ xcb_window_t win; - /** Client logical screen */ - int screen; /** Client physical screen */ int phys_screen; /** Layer in the stacking order */ @@ -299,18 +298,14 @@ struct client_node_t client_node_t *prev, *next; }; -/** Tag type */ -struct _tag_t +/** Workspace type */ +struct workspace_t { /** Ref count */ int refcount; /** Tag name */ char *name; - /** Screen */ - int screen; - /** true if selected */ - bool selected; - /** Current tag layout */ + /** Current workspace layout */ layout_t *layout; /** Master width factor */ double mwfact; @@ -318,17 +313,19 @@ struct _tag_t int nmaster; /** Number of columns in tile layout */ int ncol; - /** Next and previous tags */ - tag_t *prev, *next; + /** True if we need to arrange() */ + bool need_arrange; + /** Next and previous workspaces */ + workspace_t *prev, *next; }; /** Tag client link type */ -struct tag_client_node_t +struct workspace_client_node_t { - tag_t *tag; + workspace_t *workspace; client_t *client; - /** Next and previous tag_client_nodes */ - tag_client_node_t *prev, *next; + /** Next and previous workspace_client_nodes */ + workspace_client_node_t *prev, *next; }; /** Padding type */ @@ -344,16 +341,15 @@ typedef struct int right; } padding_t; +/** An awesome screen. */ typedef struct { - /** true if we need to arrange() */ - bool need_arrange; - /** Tag list */ - tag_t *tags; /** Status bar */ statusbar_t *statusbar; /** Padding */ padding_t padding; + /** Visible workspace */ + workspace_t *workspace; } screen_t; /** Main configuration structure */ @@ -402,8 +398,8 @@ struct awesome_t client_node_t *focus; /** Stack client history */ client_node_t *stack; - /** Link between tags and clients */ - tag_client_node_t *tclink; + /** Link between workspaces and clients */ + workspace_client_node_t *wclink; /** Command line passed to awesome */ char *argv; /** Last XMotionEvent coords */ @@ -442,6 +438,8 @@ struct awesome_t } hooks; /** The timeout after which we need to stop select() */ struct timeval timer; + /** Workspace list */ + workspace_t *workspaces; }; #endif diff --git a/tag.c b/tag.c deleted file mode 100644 index 5550f41b..00000000 --- a/tag.c +++ /dev/null @@ -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 diff --git a/titlebar.c b/titlebar.c index 324e2db1..e0530361 100644 --- a/titlebar.c +++ b/titlebar.c @@ -28,6 +28,7 @@ #include "client.h" #include "screen.h" #include "widget.h" +#include "workspace.h" #include "layouts/floating.h" 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, - 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); switch(c->titlebar->position) diff --git a/widget.c b/widget.c index 207292bc..751d34cf 100644 --- a/widget.c +++ b/widget.c @@ -248,24 +248,25 @@ widget_common_new(widget_t *widget) /** Invalidate widgets which should be refresh upon * external modifications. widget_t who watch flags will * be set to be refreshed. - * \param screen Virtual screen number. * \param flags Cache flags to invalidate. */ void -widget_invalidate_cache(int screen, int flags) +widget_invalidate_cache(int flags) { statusbar_t *statusbar; widget_node_t *widget; + int screen; - for(statusbar = globalconf.screens[screen].statusbar; - statusbar; - statusbar = statusbar->next) - for(widget = statusbar->widgets; widget; widget = widget->next) - if(widget->widget->cache_flags & flags) - { - statusbar->need_update = true; - break; - } + for(screen = 0; screen < globalconf.screens_info->nscreen; screen++) + for(statusbar = globalconf.screens[screen].statusbar; + statusbar; + statusbar = statusbar->next) + for(widget = statusbar->widgets; widget; widget = widget->next) + if(widget->widget->cache_flags & flags) + { + statusbar->need_update = true; + break; + } } /** Set a statusbar needs update because it has widget, or redraw a titlebar. diff --git a/widget.h b/widget.h index c4746892..79ad42c0 100644 --- a/widget.h +++ b/widget.h @@ -27,12 +27,12 @@ #define WIDGET_CACHE_CLIENTS 1<<0 #define WIDGET_CACHE_LAYOUTS 1<<1 -#define WIDGET_CACHE_TAGS 1<<2 -#define WIDGET_CACHE_ALL (WIDGET_CACHE_CLIENTS | WIDGET_CACHE_LAYOUTS | WIDGET_CACHE_TAGS) +#define WIDGET_CACHE_WORKSPACES 1<<2 +#define WIDGET_CACHE_ALL (WIDGET_CACHE_CLIENTS | WIDGET_CACHE_LAYOUTS | WIDGET_CACHE_WORKSPACES) 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); void widget_common_new(widget_t *); 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 *); -widget_constructor_t taglist_new; +widget_constructor_t workspacelist_new; widget_constructor_t textbox_new; widget_constructor_t iconbox_new; widget_constructor_t progressbar_new; diff --git a/widgets/tasklist.c b/widgets/tasklist.c index fbd99093..11833dd7 100644 --- a/widgets/tasklist.c +++ b/widgets/tasklist.c @@ -25,7 +25,6 @@ #include "screen.h" #include "event.h" #include "ewmh.h" -#include "tag.h" #include "common/configopts.h" #include "common/markup.h" @@ -34,7 +33,7 @@ extern awesome_t globalconf; typedef enum { ShowFocus, - ShowTags, + ShowWorkspace, ShowAll, } showclient_t; @@ -54,11 +53,11 @@ tasklist_isvisible(client_t *c, int screen, showclient_t show) switch(show) { case ShowAll: - return (c->screen == screen); - case ShowTags: + return true; + case ShowWorkspace: return client_isvisible(c, screen); case ShowFocus: - return (c == focus_get_current_client(screen)); + return (c == focus_client_getcurrent(screen)); } 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); else if(!a_strcmp(property, "show")) { - if(!a_strcmp(new_value, "tags")) - d->show = ShowTags; + if(!a_strcmp(new_value, "workspace")) + d->show = ShowWorkspace; else if(!a_strcmp(new_value, "focus")) d->show = ShowFocus; 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_urgent = a_strdup(" <title/> "); d->show_icons = true; - d->show = ShowTags; + d->show = ShowWorkspace; /* Set cache property */ w->cache_flags = WIDGET_CACHE_CLIENTS; diff --git a/widgets/taglist.c b/widgets/workspacelist.c similarity index 63% rename from widgets/taglist.c rename to widgets/workspacelist.c index b61875b3..85ccc758 100644 --- a/widgets/taglist.c +++ b/widgets/workspacelist.c @@ -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> * * This program is free software; you can redistribute it and/or modify @@ -21,7 +22,7 @@ #include "client.h" #include "widget.h" -#include "tag.h" +#include "workspace.h" #include "lua.h" #include "event.h" #include "common/markup.h" @@ -29,26 +30,26 @@ extern awesome_t globalconf; -typedef struct taglist_drawn_area_t taglist_drawn_area_t; -struct taglist_drawn_area_t +typedef struct workspacelist_drawn_area_t workspacelist_drawn_area_t; +struct workspacelist_drawn_area_t { void *object; 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 { char *text_normal, *text_focus, *text_urgent; bool show_empty; - taglist_drawn_area_t *drawn_area; + workspacelist_drawn_area_t *drawn_area; -} taglist_data_t; +} workspacelist_data_t; 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 }; 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; } -/** Check if at least one client is tagged with tag number t and is on screen - * screen - * \param t tag - * \return true or false +/** Check if at least one client is on the workspace. + * \param ws The workspace. + * \return True or false. */ static bool -tag_isoccupied(tag_t *t) +workspace_isoccupied(workspace_t *ws) { client_t *c; 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 false; } static bool -tag_isurgent(tag_t *t) +workspace_isurgent(workspace_t *ws) { client_t *c; 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 false; } 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; - else if(tag_isurgent(tag)) + + if(workspace_isurgent(ws)) return data->text_urgent; return data->text_normal; } static int -taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w, - int offset, - int used __attribute__ ((unused)), - void *object) +workspacelist_draw(draw_context_t *ctx, int screen, + widget_node_t *w, + int offset, + int used __attribute__ ((unused)), + void *object) { - tag_t *tag; - taglist_data_t *data = w->widget->data; - client_t *sel = globalconf.focus->client; - screen_t *vscreen = &globalconf.screens[screen]; + workspace_t *ws; + workspacelist_data_t *data = w->widget->data; int i = 0, prev_width = 0; area_t *area, rectangle = { 0, 0, 0, 0, NULL, NULL }; char **text = NULL; - taglist_drawn_area_t *tda; + workspacelist_drawn_area_t *tda; w->area.width = w->area.y = 0; - /* Lookup for our taglist_drawn_area. - * This will be used to store area where we draw tag list for each object. */ + /* Lookup for our workspacelist_drawn_area. + * 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); /* Oh, we did not find a drawn area for our object. First time? */ if(!tda) { /** \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; - taglist_drawn_area_list_push(&data->drawn_area, tda); + workspacelist_drawn_area_list_push(&data->drawn_area, tda); } area_list_wipe(&tda->area); /* 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); area = p_new(area_t, 1); - text[i] = taglist_text_get(tag, data); - text[i] = tag_markup_parse(tag, text[i], a_strlen(text[i])); + text[i] = workspacelist_text_get(ws, &globalconf.screens[screen], data); + text[i] = workspace_markup_parse(ws, text[i], a_strlen(text[i])); *area = draw_text_extents(ctx->connection, ctx->phys_screen, 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; 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, offset, w->widget->align); - for(area = tda->area, tag = vscreen->tags, i = 0; - tag && area; - tag = tag->next, area = area->next, i++) + for(area = tda->area, ws = globalconf.workspaces, i = 0; + ws && area; + ws = ws->next, area = area->next, i++) { - if (!data->show_empty && !tag->selected && !tag_isoccupied(tag)) + if (!data->show_empty && !workspace_isoccupied(ws)) continue; 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]); p_delete(&text[i]); - if(tag_isoccupied(tag)) + if(workspace_isoccupied(ws)) { rectangle.width = rectangle.height = (globalconf.font->height + 2) / 3; rectangle.x = area->x; rectangle.y = area->y; - draw_rectangle(ctx, rectangle, 1.0, - sel && is_client_tagged(sel, tag), ctx->fg); + draw_rectangle(ctx, rectangle, 1.0, false, ctx->fg); } } @@ -200,18 +199,17 @@ taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w, * \param type The type object. */ static void -taglist_button_press(widget_node_t *w, - xcb_button_press_event_t *ev, - int screen, - void *object, - awesome_type_t type) +workspacelist_button_press(widget_node_t *w, + xcb_button_press_event_t *ev, + int screen __attribute__ ((unused)), + void *object, + awesome_type_t type) { - screen_t *vscreen = &globalconf.screens[screen]; button_t *b; - taglist_data_t *data = w->widget->data; - taglist_drawn_area_t *tda; + workspacelist_data_t *data = w->widget->data; + workspacelist_drawn_area_t *tda; area_t *area; - tag_t *tag; + workspace_t *ws; /* Find the good drawn area list */ 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) 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) && 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_tag_userdata_new(tag); + luaA_workspace_userdata_new(ws); luaA_dofunction(globalconf.L, b->fct, 2); return; } } 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")) { @@ -260,26 +258,26 @@ taglist_tell(widget_t *widget, const char *property, const char *new_value) } widget_t * -taglist_new(alignment_t align) +workspacelist_new(alignment_t align) { widget_t *w; - taglist_data_t *d; + workspacelist_data_t *d; w = p_new(widget_t, 1); widget_common_new(w); w->align = align; - w->draw = taglist_draw; - w->button_press = taglist_button_press; - w->tell = taglist_tell; + w->draw = workspacelist_draw; + w->button_press = workspacelist_button_press; + 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_focus = a_strdup(" <text align=\"center\"/><title/> "); d->text_urgent = a_strdup(" <text align=\"center\"/><title/> "); d->show_empty = true; /* Set cache property */ - w->cache_flags = WIDGET_CACHE_TAGS | WIDGET_CACHE_CLIENTS; + w->cache_flags = WIDGET_CACHE_WORKSPACES | WIDGET_CACHE_CLIENTS; return w; } diff --git a/workspace.c b/workspace.c new file mode 100644 index 00000000..85f72de5 --- /dev/null +++ b/workspace.c @@ -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 diff --git a/tag.h b/workspace.h similarity index 63% rename from tag.h rename to workspace.h index cde5759d..74b91df9 100644 --- a/tag.h +++ b/workspace.h @@ -1,5 +1,5 @@ /* - * tag.h - tag management header + * workspace.h - workspace management header * * Copyright © 2007-2008 Julien Danjou <julien@danjou.info> * @@ -19,8 +19,8 @@ * */ -#ifndef AWESOME_TAG_H -#define AWESOME_TAG_H +#ifndef AWESOME_WORKSPACE_H +#define AWESOME_WORKSPACE_H #include "structs.h" #include "common/refcount.h" @@ -29,28 +29,26 @@ #define IS_TILED(client, screen) (client && !client->isfloating && !client->ismax && client_isvisible(client, screen)) /* 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 -tag_delete(tag_t **tag) +workspace_delete(workspace_t **workspace) { - p_delete(&(*tag)->name); - p_delete(tag); + p_delete(&(*workspace)->name); + p_delete(workspace); } -tag_t ** tags_get_current(int); -void tag_client(client_t *, tag_t *); -void untag_client(client_t *, tag_t *); -bool is_client_tagged(client_t *, tag_t *); -void tag_client_with_current_selected(client_t *); -void tag_view_only_byindex(int, int); -void tag_append_to_screen(tag_t *, int); -int luaA_tag_userdata_new(tag_t *); +void workspace_client_set(client_t *, workspace_t *); +workspace_t * workspace_client_get(client_t *); +void workspace_client_remove(client_t *); +int workspace_screen_get(workspace_t *); -DO_RCNT(tag_t, tag, tag_delete) -DO_SLIST(tag_t, tag, tag_delete) +int luaA_workspace_userdata_new(workspace_t *); -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 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80