diff --git a/Makefile.am b/Makefile.am index a6b8347e4..dcec6e154 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,7 +32,7 @@ LAYOUTS += layouts/magnifier.c LAYOUTS += layouts/magnifier.h WIDGETS = -WIDGETS += widgets/workspacelist.c +WIDGETS += widgets/taglist.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 \ - workspace.c workspace.h \ + tag.c tag.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 11474c935..82abab590 100644 --- a/awesome-client.1.txt +++ b/awesome-client.1.txt @@ -26,6 +26,7 @@ awesome-client reads commands from standard input. When you pipe multiple lines into awesome-client, an empty line will flush already 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 50edfcb0b..7d106a9e1 100644 --- a/awesome.1.txt +++ b/awesome.1.txt @@ -26,13 +26,17 @@ regardless of the layout applied. The spiral and dwindle layout are special case of the tiled layout where the stacking area is arranged in a spiral for the former or as a rectangular fractal for the later. -Windows are grouped in workspacess. +Windows are grouped by tags. Each window can be tagged with one or multiple +tags. Selecting certain tags displays all windows with these tags. -awesome contains a small status bar which displays all available workspaces, -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 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 floating window is indicated with a circle square before the windows -title. The selected workspace is indicated with a different color. +title. The selected tags are indicated with a different color. The tags of +the focused window are indicated with a filled square in the top left +corner. The tags which are applied to one or more windows are indicated +with an empty square in the top left corner. awesome can draw a small border around windows to indicate the focus state. OPTIONS @@ -46,12 +50,20 @@ OPTIONS DEFAULTS MOUSE BINDINGS ----------------------- -*Button1* on workspace name:: - View workspace. +*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*, *Button3*, *Button4*, *Button5* on layout symbol:: Switch to previous or next layout. *Button4*, *Button5* on root window:: - Switch to previous or next workspace. + Switch to previous or next tag. *Mod4 + Button1* on client window:: Move window. *Mod4 + Button3* on client window:: @@ -89,10 +101,12 @@ 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 workspace. + View previous tag. *Mod4 + Right*:: - View next workspace. + View next tag. *Mod4 \+ Control \+ space*:: Set client floating. *Mod4 \+ Shift \+ c*:: @@ -102,9 +116,13 @@ DEFAULTS KEY BINDINGS *Mod4 \+ Control \+ r*:: Restart awesome. *Mod4 + 1-9*:: - Switch to workspace 1-9. + Switch to tag 1-9. +*Mod4 \+ Control \+ 1-9*:: + Toggle tag view. *Mod4 \+ Shift \+ 1-9*:: - Move client to workspace 1-9. + Tag client with tag. +*Mod4 \+ Shift \+ Control \+ 1-9*:: + Toggle tag on client. CUSTOMIZATION ------------- diff --git a/awesome.c b/awesome.c index 0b7f565b8..ae8d40048 100644 --- a/awesome.c +++ b/awesome.c @@ -52,6 +52,7 @@ #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 491dac8ae..b957268b4 100644 --- a/awesomerc.lua.in +++ b/awesomerc.lua.in @@ -21,25 +21,33 @@ modkey = "Mod4" layouts = { "tile", "tileleft", "tilebottom", "tiletop", "magnifier", "max", "spiral", "dwindle", "floating" } -- }}} --- {{{ Workspaces --- Define workspaces table -workspaces = {} --- Create 9 workspaces -for i = 1, 9 do - workspaces[i] = workspace.new({ name = i }) - workspaces[i]:add(s) +-- {{{ 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) end --- I'm sure you want to see at least one workspace -workspaces[1]:screen_set(1) -- }}} -- {{{ Statusbar --- 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", " ") +-- 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", "<bg color=\"#555555\"/> <title/> ") -- Create a tasklist widget mytasklist = widget.new({ type = "tasklist", name = "mytasklist" }) @@ -74,7 +82,7 @@ for s = 1, screen.count() do mystatusbar = statusbar.new({ position = "top", name = "mystatusbar" .. s, fg = "lightblue", bg = "black" }) -- Add widgets to the statusbar - order matters - mystatusbar:widget_add(myworkspacelist) + mystatusbar:widget_add(mytaglist) mystatusbar:widget_add(myiconbox) mystatusbar:widget_add(mytasklist) mystatusbar:widget_add(mytextbox) @@ -85,8 +93,8 @@ end -- {{{ Mouse bindings awesome.mouse({ }, 3, function () awful.spawn(terminal) end) -awesome.mouse({ }, 4, awful.workspace.viewnext) -awesome.mouse({ }, 5, awful.workspace.viewprev) +awesome.mouse({ }, 4, awful.tag.viewnext) +awesome.mouse({ }, 5, awful.tag.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) @@ -96,20 +104,44 @@ 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 = math.min(9, #workspaces); +keynumber = 0 +for s = 1, screen.count() do + keynumber = math.min(9, math.max(#tags[s], keynumber)); +end + for i = 1, keynumber do keybinding.new({ modkey }, i, function () - workspaces[i]:screen_set(mouse.screen_get()) + local screen = mouse.screen_get() + if tags[screen][i] then + awful.tag.viewonly(tags[screen][i]) + end + end):add() + keybinding.new({ modkey, "Control" }, i, + function () + local screen = mouse.screen_get() + if tags[screen][i] then + tags[i]:view(not tags[screen][i]:isselected()) + end end):add() keybinding.new({ modkey, "Shift" }, i, function () - client.focus_get():workspace_set(workspaces[i]) + local screen = mouse.screen_get() + if tags[screen][i] then + awful.client.movetotag(tags[screen][i]) + end + end):add() + keybinding.new({ modkey, "Control", "Shift" }, i, + function () + local screen = mouse.screen_get() + if tags[screen][i] then + awful.client.toggletag(tags[screen][i]) + end end):add() end -keybinding.new({ modkey }, "Left", awful.workspace.viewprev):add() -keybinding.new({ modkey }, "Right", awful.workspace.viewnext):add() +keybinding.new({ modkey }, "Left", awful.tag.viewprev):add() +keybinding.new({ modkey }, "Right", awful.tag.viewnext):add() -- Standard program keybinding.new({ modkey }, "Return", function () awful.spawn(terminal) end):add() @@ -129,12 +161,12 @@ keybinding.new({ modkey, "Control" }, "space", awful.client.togglefloating):add( keybinding.new({ modkey }, "o", awful.client.movetoscreen):add() -- Layout manipulation -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 }, "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 }, "space", function () awful.layout.inc(layouts, 1) end):add() keybinding.new({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end):add() -- }}} @@ -153,7 +185,7 @@ end -- Hook function to exeucte when the mouse is over a client. function hook_mouseover(c) -- Sloppy focus, but disabled for magnifier layout - if c:workspace_get():layout_get() ~= "magnifier" then + if awful.layout.get(c:screen_get()) ~= "magnifier" then c:focus_set() end end @@ -170,10 +202,10 @@ function hook_newclient(c) end -- Hook function to execute when arranging the screen --- (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") +-- (tag switch, new client, etc) +function hook_arrange(screen) + local layout = awful.layout.get(screen) + mylayoutbox[screen]:set("image", "@iconsdir@/layouts/" .. layout .. "w.png") end -- Hook called every second diff --git a/awful.lua b/awful.lua index ec5e09778..a512858c0 100644 --- a/awful.lua +++ b/awful.lua @@ -20,7 +20,7 @@ local pairs = pairs local awesome = awesome local screen = screen local client = client -local workspace = workspace +local tag = tag local mouse = mouse local os = os local table = table @@ -84,7 +84,13 @@ function client_moveresize(x, y, w, h) end function screen_focus(i) - local s = mouse.screen_get() + local sel = client.focus_get() + local s + if sel then + s = sel:screen_get() + else + s = mouse.screen_get() + end local count = screen.count() s = s + i if s < 1 then @@ -92,81 +98,136 @@ function screen_focus(i) elseif s > count then s = 1 end - local ws = screen.workspace_get(s) - if ws then - ws:focus_set() - end + screen.focus(s) -- 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 workspace_setmwfact(i) - local t = workspace_selected() +function tag_setmwfact(i) + local t = tag_selected() if t then t:mwfact_set(i) end end -- Increase master width factor -function workspace_incmwfact(i) - local t = workspace_selected() +function tag_incmwfact(i) + local t = tag_selected() if t then t:mwfact_set(t:mwfact_get() + i) end end -- Set number of master windows -function workspace_setnmaster(i) - local t = workspace_selected() +function tag_setnmaster(i) + local t = tag_selected() if t then t:nmaster_set(i) end end -- Increase number of master windows -function workspace_incnmaster(i) - local t = workspace_selected() +function tag_incnmaster(i) + local t = tag_selected() if t then t:nmaster_set(t:nmaster_get() + i) end end -- Set number of column windows -function workspace_setncol(i) - local t = workspace_selected() +function tag_setncol(i) + local t = tag_selected() if t then t:ncol_set(i) end end -- Increase number of column windows -function workspace_incncol(i) - local t = workspace_selected() +function tag_incncol(i) + local t = tag_selected() if t then t:ncol_set(t:ncol_get() + i) end end -function workspace_viewidx(r) - local workspaces = workspace.get() - local sel = workspace.visible_get(mouse.screen_get()) - for i, t in ipairs(workspaces) do +-- 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 if t == sel then - workspaces[array_boundandcycle(workspaces, i + r)]:screen_set(mouse.screen_get()) + tags[array_boundandcycle(tags, i + r)]:view(true) end end end --- View next workspace -function workspace_viewnext() - return workspace_viewidx(1) +-- View next tag +function tag_viewnext() + return tag_viewidx(1) end --- View previous workspace -function workspace_viewprev() - return workspace_viewidx(-1) +-- 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 end function client_togglefloating(c) @@ -189,11 +250,18 @@ function client_movetoscreen(c, s) end end --- Function to change the layout of the current workspace. +function layout_get(screen) + local t = tag_selected(screen) + if t then + return t:layout_get() + end +end + +-- Function to change the layout of the current tag. -- layouts = table of layouts (define in .awesomerc.lua) -- i = relative index function layout_inc(layouts, i) - local t = workspace.visible_get(mouse.screen_get()) + local t = tag_selected() local number_of_layouts = 0 local rev_layouts = {} for i, v in ipairs(layouts) do @@ -201,7 +269,7 @@ function layout_inc(layouts, i) number_of_layouts = number_of_layouts + 1 end if t then - local cur_layout = t:layout_get() + local cur_layout = layout_get() local new_layout_index = (rev_layouts[cur_layout] + i) % number_of_layouts if new_layout_index == 0 then new_layout_index = number_of_layouts @@ -210,9 +278,9 @@ function layout_inc(layouts, i) end end --- function to set the layout of the current workspace by name. +-- function to set the layout of the current tag by name. function layout_set(layout) - local t = workspace.visible_get(mouse.screen_get()) + local t = tag_selected() if t then t:layout_set(layout) end @@ -272,24 +340,30 @@ function spawn(cmd) return os.execute(cmd .. "&") end --- Export workspaces function -P.workspace = +-- Export tags function +P.tag = { - viewprev = workspace_viewprev; - viewnext = workspace_viewnext; - setmwfact = workspace_setmwfact; - incmwfact = workspace_incmwfact; - setncol = workspace_setncol; - incncol = workspace_incncol; - setnmaster = workspace_setnmaster; - incnmaster = workspace_incnmaster; + 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; } P.client = { next = client_next; focus = client_focus; swap = client_swap; - movetoworkspace = client_movetoworkspace; + movetotag = client_movetotag; + toggletag = client_toggletag; togglefloating = client_togglefloating; moveresize = client_moveresize; movetoscreen = client_movetoscreen; @@ -300,6 +374,7 @@ P.screen = } P.layout = { + get = layout_get; set = layout_set; inc = layout_inc; } diff --git a/client.c b/client.c index 923298ad1..bb552fb69 100644 --- a/client.c +++ b/client.c @@ -27,7 +27,7 @@ #include <xcb/shape.h> #include "client.h" -#include "workspace.h" +#include "tag.h" #include "window.h" #include "focus.h" #include "ewmh.h" @@ -44,40 +44,40 @@ extern awesome_t globalconf; -/** Load windows properties, restoring client's workspace +/** Load windows properties, restoring client's tag * and floating state before awesome was restarted if any. - * \todo This may bug if number of workspacess is != than before. + * \todo This may bug if number of tags is != than before. * \param c A client pointer. + * \param screen A virtual screen number. * \return True if client had property, false otherwise. */ static bool -client_loadprops(client_t * c) +client_loadprops(client_t * c, int screen) { - int i, nworkspaces = 0; - workspace_t *workspace; + int i, ntags = 0; + tag_t *tag; char *prop = NULL; bool result = false; - xutil_intern_atom_request_t atom_q; - atom_q = xutil_intern_atom(globalconf.connection, &globalconf.atoms, "_AWESOME_PROPERTIES"); - - for(workspace = globalconf.workspaces; workspace; workspace = workspace->next) - nworkspaces++; + for(tag = globalconf.screens[screen].tags; tag; tag = tag->next) + ntags++; if(xutil_gettextprop(globalconf.connection, c->win, &globalconf.atoms, - xutil_intern_atom_reply(globalconf.connection, &globalconf.atoms, atom_q), + xutil_intern_atom_reply(globalconf.connection, &globalconf.atoms, + xutil_intern_atom(globalconf.connection, + &globalconf.atoms, + "_AWESOME_PROPERTIES")), &prop)) { - for(i = 0, workspace = globalconf.workspaces; workspace && i < nworkspaces && prop[i]; i++, workspace = workspace->next) + for(i = 0, tag = globalconf.screens[screen].tags; tag && i < ntags && prop[i]; i++, tag = tag->next) if(prop[i] == '1') { - workspace_client_set(c, workspace); + tag_client(c, tag); 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,42 +115,43 @@ window_isprotodel(xcb_window_t win) return ret; } -/** Returns true if a client is on a workspace visible +/** Returns true if a client is tagged with one of the tags visibl * on any screen. * \param c The client. - * \return True if client is visible, false otherwise. + * \return True if client is tagged, false otherwise. */ static bool client_isvisible_anyscreen(client_t *c) { - workspace_t *ws; + tag_t *tag; int screen; if(c && !c->ishidden) - { - ws = workspace_client_get(c); for(screen = 0; screen < globalconf.screens_info->nscreen; screen++) - if(globalconf.screens[screen].workspace == ws) - return true; - } + for(tag = globalconf.screens[screen].tags; tag; tag = tag->next) + if(tag->selected && is_client_tagged(c, tag)) + return true; return false; } -/** Returns true if a client is on the workspace visible on the specified - * screen. +/** Returns true if a client is tagged + * with one of the tags of 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) { - if(c && !c->ishidden) - return (workspace_client_get(c) == globalconf.screens[screen].workspace); + tag_t *tag; + + if(c && !c->ishidden && c->screen == screen) + for(tag = globalconf.screens[screen].tags; tag; tag = tag->next) + if(tag->selected && is_client_tagged(c, tag)) + return true; return false; } - /** Get a client by its window. * \param w The client window to find. * \return A client pointer if found, NULL otherwise. @@ -193,18 +194,18 @@ client_updatetitle(client_t *c) luaA_client_userdata_new(c); luaA_dofunction(globalconf.L, globalconf.hooks.titleupdate, 1); - widget_invalidate_cache(WIDGET_CACHE_CLIENTS); + widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); } static void client_unfocus(client_t *c) { /* Call hook */ - luaA_client_userdata_new(c); + luaA_client_userdata_new(globalconf.focus->client); luaA_dofunction(globalconf.L, globalconf.hooks.unfocus, 1); focus_client_push(NULL); - widget_invalidate_cache(WIDGET_CACHE_CLIENTS); + widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); } /** Ban client and unmap it @@ -223,40 +224,55 @@ client_ban(client_t *c) /** Give focus to client, or to first client if client is NULL, * \param c The client or NULL. - * \return True if a window (even root). + * \param screen Virtual screen number. + * \return True if a window (even root) has received focus, false otherwise. */ bool -client_focus(client_t *c) +client_focus(client_t *c, int screen) { int phys_screen; - if(!c) - return false; + /* 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); /* unfocus current selected client */ if(globalconf.focus->client) client_unfocus(globalconf.focus->client); - /* 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; + 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; - /* Some layouts use focused client differently, so call them back. */ - workspace_client_get(c)->need_arrange = true; + /* Some layouts use focused client differently, so call them back. */ + globalconf.screens[c->screen].need_arrange = true; - /* execute hook */ - luaA_client_userdata_new(globalconf.focus->client); - luaA_dofunction(globalconf.L, globalconf.hooks.focus, 1); + /* 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); + } ewmh_update_net_active_window(phys_screen); - widget_invalidate_cache(WIDGET_CACHE_CLIENTS); + widget_invalidate_cache(screen, WIDGET_CACHE_CLIENTS); return true; } @@ -312,20 +328,20 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int screen) client_t *c, *t = NULL; 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); - rscreen = screen_get_bycoord(globalconf.screens_info, screen, wgeom->x, wgeom->y); + c->screen = screen_get_bycoord(globalconf.screens_info, screen, wgeom->x, wgeom->y); if(globalconf.screens_info->xinerama_is_active) c->phys_screen = globalconf.default_screen; else - c->phys_screen = rscreen; + c->phys_screen = c->screen; /* Initial values */ c->win = w; @@ -341,16 +357,18 @@ 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))) - workspace_client_set(c, globalconf.screens[screen].workspace); + if(!(retloadprops = client_loadprops(c, screen))) + screen_client_moveto(c, screen, true); /* Then check clients hints */ ewmh_check_client_hints(c); - /* check for transient and set on same workspace like its parent */ + /* check for transient and set tags like its parent */ if((rettrans = xutil_get_transient_for_hint(globalconf.connection, w, &trans)) && (t = client_getbywin(trans))) - workspace_client_set(c, workspace_client_get(t)); + for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next) + if(is_client_tagged(t, tag)) + tag_client(c, tag); /* should be floating if transsient or fixed */ if(rettrans || c->isfixed) @@ -388,7 +406,7 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, int screen) /* Push client in stack */ stack_client_push(c); - widget_invalidate_cache(WIDGET_CACHE_CLIENTS); + widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); ewmh_update_net_client_list(c->phys_screen); /* update window title */ @@ -455,16 +473,15 @@ client_geometry_hints(client_t *c, area_t geometry) bool client_resize(client_t *c, area_t geometry, bool hints) { - int screen, new_screen; - workspace_t *ws; + int new_screen; + area_t area; + layout_t *layout = layout_get_current(c->screen); bool resized = false; /* Values to configure a window is an array where values are * stored according to 'value_mask' */ uint32_t values[5]; - ws = workspace_client_get(c); - - if(c->titlebar && !c->ismoving && !c->isfloating && ws->layout != layout_floating) + if(c->titlebar && !c->ismoving && !c->isfloating && layout != layout_floating) { titlebar_update_geometry(c, geometry); geometry = titlebar_geometry_remove(c->titlebar, geometry); @@ -476,12 +493,24 @@ client_resize(client_t *c, area_t geometry, bool hints) if(geometry.width <= 0 || geometry.height <= 0) 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, screen, geometry.x, geometry.y); + screen_get_bycoord(globalconf.screens_info, c->screen, geometry.x, geometry.y); c->geometry.x = values[0] = geometry.x; c->geometry.width = values[2] = geometry.width; @@ -492,7 +521,7 @@ client_resize(client_t *c, area_t geometry, bool hints) /* save the floating geometry if the window is floating but not * maximized */ if(c->ismoving || c->isfloating - || ws->layout == layout_floating) + || layout_get_current(new_screen) == layout_floating) { titlebar_update_geometry_floating(c); if(!c->ismax) @@ -506,12 +535,15 @@ 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 && ws->layout != layout_floating) + if(!c->ismoving && !c->isfloating && layout != layout_floating) titlebar_update_geometry_floating(c); return resized; @@ -534,8 +566,9 @@ client_setfloating(client_t *c, bool floating, layer_t layer) c->ismax = false; client_resize(c, c->m_geometry, false); } - workspace_client_get(c)->need_arrange = true; - widget_invalidate_cache(WIDGET_CACHE_CLIENTS); + if(client_isvisible(c, c->screen)) + globalconf.screens[c->screen].need_arrange = true; + widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); if(floating) { c->oldlayer = c->layer; @@ -554,23 +587,20 @@ client_setfloating(client_t *c, bool floating, layer_t layer) void client_saveprops(client_t *c) { - int i = 0, nws = 0; + int i = 0, ntags = 0; char *prop; - workspace_t *workspace, *cws = workspace_client_get(c); + tag_t *tag; xutil_intern_atom_request_t atom_q; atom_q = xutil_intern_atom(globalconf.connection, &globalconf.atoms, "_AWESOME_PROPERTIES"); - for(workspace = globalconf.workspaces; workspace; workspace = workspace->next) - nws++; + for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next) + ntags++; - prop = p_new(char, nws + 3); + prop = p_new(char, ntags + 3); - for(workspace = globalconf.workspaces; workspace; workspace = workspace->next, i++) - if(cws == workspace) - prop[i] = '1'; - else - prop[i] = '0'; + for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next, i++) + prop[i] = is_client_tagged(c, tag) ? '1' : '0'; prop[i] = c->isfloating ? '1' : '0'; @@ -597,6 +627,8 @@ 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); @@ -608,11 +640,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(focus_client_getcurrent(workspace_client_get(c))); - - workspace_client_remove(c); + client_focus(NULL, c->screen); xcb_ungrab_button(globalconf.connection, XCB_BUTTON_INDEX_ANY, c->win, ANY_MODIFIER); window_setstate(c->win, XCB_WM_WITHDRAWN_STATE); @@ -647,7 +679,7 @@ client_updatewmhints(client_t *c) luaA_client_userdata_new(c); luaA_dofunction(globalconf.L, globalconf.hooks.urgent, 1); - widget_invalidate_cache(WIDGET_CACHE_CLIENTS); + widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); } if((wm_hints_flags & XCB_WM_STATE_HINT) && (xcb_wm_hints_get_initial_state(wmh) == XCB_WM_WITHDRAWN_STATE)) @@ -883,7 +915,7 @@ client_setborder(client_t *c, uint32_t width) c->border = width; xcb_configure_window(globalconf.connection, c->win, XCB_CONFIG_WINDOW_BORDER_WIDTH, &width); - workspace_client_get(c)->need_arrange = true; + globalconf.screens[c->screen].need_arrange = true; } /** Set the client border width and color. @@ -908,28 +940,64 @@ luaA_client_border_set(lua_State *L) return 0; } -/** Set the client on the specified workspace. - * \param A workspace object. +/** Move the client to another screen. + * \param A screen number. */ static int -luaA_client_workspace_set(lua_State *L) +luaA_client_screen_set(lua_State *L) { client_t **c = luaA_checkudata(L, 1, "client"); - workspace_t **workspace = luaA_checkudata(L, 2, "workspace"); - /* arrange old ws */ - workspace_client_get(*c)->need_arrange = true; - workspace_client_set(*c, *workspace); + int screen = luaL_checknumber(L, 2) - 1; + luaA_checkscreen(screen); + screen_client_moveto(*c, screen, true); return 0; } -/** Get the workspace the client is on. - * \return A workspace. +/** Get the screen number the client is onto. + * \return A screen number. */ static int -luaA_client_workspace_get(lua_State *L) +luaA_client_screen_get(lua_State *L) { client_t **c = luaA_checkudata(L, 1, "client"); - return luaA_workspace_userdata_new(workspace_client_get(*c)); + lua_pushnumber(L, 1 + (*c)->screen); + return 1; +} + +/** Tag a client with a specified tag. + * \param A tag object. + * \param A boolean value: true to add this tag to clients, false to remove. + */ +static int +luaA_client_tag(lua_State *L) +{ + client_t **c = luaA_checkudata(L, 1, "client"); + tag_t **tag = luaA_checkudata(L, 2, "tag"); + bool tag_the_client = luaA_checkboolean(L, 3); + + if((*tag)->screen != (*c)->screen) + luaL_error(L, "tag and client are on different screens"); + + if(tag_the_client) + tag_client(*c, *tag); + else + untag_client(*c, *tag); + + return 0; +} + +/** Check if a client is tagged with the specified tag. + * \param A tag object. + * \return A boolean value, true if the client is tagged with this tag, false + * otherwise. + */ +static int +luaA_client_istagged(lua_State *L) +{ + client_t **c = luaA_checkudata(L, 1, "client"); + tag_t **tag = luaA_checkudata(L, 2, "tag"); + lua_pushboolean(L, is_client_tagged(*c, *tag)); + return 1; } /** Get the client coordinates on the display. @@ -957,7 +1025,7 @@ luaA_client_coords_set(lua_State *L) client_t **c = luaA_checkudata(L, 1, "client"); area_t geometry; - if((*c)->isfloating || workspace_client_get(*c)->layout == layout_floating) + if((*c)->isfloating || layout_get_current((*c)->screen) == layout_floating) { luaA_checktable(L, 2); geometry.x = luaA_getopt_number(L, 2, "x", (*c)->geometry.x); @@ -995,9 +1063,10 @@ luaA_client_swap(lua_State *L) client_t **c = luaA_checkudata(L, 1, "client"); client_t **swap = luaA_checkudata(L, 2, "client"); client_list_swap(&globalconf.clients, *swap, *c); - workspace_client_get(*c)->need_arrange = true; - workspace_client_get(*swap)->need_arrange = true; - widget_invalidate_cache(WIDGET_CACHE_CLIENTS); + 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); return 0; } @@ -1005,7 +1074,7 @@ static int luaA_client_focus_set(lua_State *L) { client_t **c = luaA_checkudata(L, 1, "client"); - client_focus(*c); + client_focus(*c, (*c)->screen); return 0; } @@ -1121,7 +1190,6 @@ 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"); @@ -1135,12 +1203,10 @@ luaA_client_titlebar_set(lua_State *L) titlebar_ref(t); titlebar_init(*c); - ws = workspace_client_get(*c); - - if((*c)->isfloating || ws->layout == layout_floating) + if((*c)->isfloating || layout_get_current((*c)->screen) == layout_floating) titlebar_update_geometry_floating(*c); else - ws->need_arrange = true; + globalconf.screens[(*c)->screen].need_arrange = true; return 0; } @@ -1176,7 +1242,7 @@ luaA_client_hide(lua_State *L) { client_t **c = luaA_checkudata(L, 1, "client"); (*c)->ishidden = true; - workspace_client_get(*c)->need_arrange = true; + globalconf.screens[(*c)->screen].need_arrange = true; return 0; } @@ -1187,7 +1253,7 @@ luaA_client_unhide(lua_State *L) { client_t **c = luaA_checkudata(L, 1, "client"); (*c)->ishidden = false; - workspace_client_get(*c)->need_arrange = true; + globalconf.screens[(*c)->screen].need_arrange = true; return 0; } @@ -1213,9 +1279,11 @@ 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 }, - { "workspace_set", luaA_client_workspace_set }, - { "workspace_get", luaA_client_workspace_get }, + { "tag", luaA_client_tag }, + { "istagged", luaA_client_istagged }, { "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 29e362407..108e1a3d8 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 *); +bool client_focus(client_t *, int); void client_raise(client_t *); void client_ban(client_t *); void client_unban(client_t *); diff --git a/event.c b/event.c index c25ba163c..fa72c9980 100644 --- a/event.c +++ b/event.c @@ -25,6 +25,7 @@ #include "screen.h" #include "event.h" +#include "tag.h" #include "statusbar.h" #include "window.h" #include "mouse.h" @@ -33,7 +34,6 @@ #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, workspace_screen_get(workspace_client_get(c)), + w->widget->button_press(w, ev, c->screen, c->titlebar, AWESOME_TYPE_TITLEBAR); return 0; } @@ -181,12 +181,9 @@ 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) @@ -201,11 +198,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 || ws->layout == layout_floating) + if(c->isfloating || layout_get_current(c->screen) == layout_floating) client_resize(c, geometry, false); else { - ws->need_arrange = true; + globalconf.screens[c->screen].need_arrange = true; /* If we do not resize the client, at least tell it that it * has its new configuration. That fixes at least * gnome-terminal */ @@ -466,7 +463,6 @@ 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 */ @@ -474,11 +470,10 @@ 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))) - ws->need_arrange = true; + globalconf.screens[c->screen].need_arrange = true; } else if (ev->atom == WM_NORMAL_HINTS) client_updatesizehints(c); diff --git a/ewmh.c b/ewmh.c index 9b01460df..596df8f25 100644 --- a/ewmh.c +++ b/ewmh.c @@ -24,7 +24,7 @@ #include <xcb/xcb_aux.h> #include "ewmh.h" -#include "workspace.h" +#include "tag.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; - workspace_t *workspace; + tag_t *tag; - for(workspace = globalconf.workspaces; workspace; workspace = workspace->next) + for(tag = globalconf.screens[phys_screen].tags; tag; tag = tag->next) count++; xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, @@ -202,14 +202,16 @@ void ewmh_update_net_current_desktop(int phys_screen) { uint32_t count = 0; - workspace_t *workspace; + tag_t *tag, **curtags = tags_get_current(phys_screen); - for(workspace = globalconf.workspaces; workspace; workspace = workspace->next) + for(tag = globalconf.screens[phys_screen].tags; tag != curtags[0]; tag = tag->next) count++; 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 @@ -217,14 +219,14 @@ ewmh_update_net_desktop_names(int phys_screen) { char buf[1024], *pos; ssize_t len, curr_size; - workspace_t *workspace; + tag_t *tag; pos = buf; len = 0; - for(workspace = globalconf.workspaces; workspace; workspace = workspace->next) + for(tag = globalconf.screens[phys_screen].tags; tag; tag = tag->next) { - curr_size = a_strlen(workspace->name); - a_strcpy(pos, sizeof(buf), workspace->name); + curr_size = a_strlen(tag->name); + a_strcpy(pos, sizeof(buf), tag->name); pos += curr_size + 1; len += curr_size + 1; } @@ -238,7 +240,7 @@ void ewmh_update_net_active_window(int phys_screen) { xcb_window_t win; - client_t *sel = focus_client_getcurrent(globalconf.screens[phys_screen].workspace); + client_t *sel = focus_get_current_client(phys_screen); win = sel ? sel->win : XCB_NONE; @@ -251,11 +253,12 @@ 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) { - /* \todo support for sticky */ + tag_t *tag; + for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next) + tag_client(c, tag); } else if(state == net_wm_state_skip_taskbar) { @@ -287,8 +290,7 @@ ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set) } else if(set == _NET_WM_STATE_ADD) { - screen = workspace_screen_get(workspace_client_get(c)); - geometry = screen_area_get(screen, NULL, &globalconf.screens[screen].padding); + geometry = screen_area_get(c->screen, NULL, &globalconf.screens[c->screen].padding); /* save geometry */ c->m_geometry = c->geometry; c->wasfloating = c->isfloating; @@ -304,7 +306,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(WIDGET_CACHE_CLIENTS); + widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); client_resize(c, geometry, false); xcb_configure_window(globalconf.connection, c->win, XCB_CONFIG_WINDOW_STACK_MODE, &raise_window_val); } @@ -365,21 +367,17 @@ ewmh_process_client_message(xcb_client_message_event_t *ev) { client_t *c; 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) - { - 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) + tag_view_only_byindex(screen, ev->data.data32[0]); + } + + if(ev->type == net_close_window) { if((c = client_getbywin(ev->window))) client_kill(c); diff --git a/focus.c b/focus.c index e2152f52c..acb64bb45 100644 --- a/focus.c +++ b/focus.c @@ -21,7 +21,7 @@ #include "focus.h" #include "cnode.h" -#include "workspace.h" +#include "tag.h" extern awesome_t globalconf; @@ -61,28 +61,33 @@ focus_client_delete(client_t *c) } static client_t * -focus_get_latest_client_for_workspace(workspace_t *ws, int nindex) +focus_get_latest_client_for_tags(tag_t **t, int nindex) { client_node_t *node; + tag_t **tags; int i = 0; for(node = globalconf.focus; node; node = node->next) if(node->client && !node->client->skip && !node->client->ishidden) - if(workspace_client_get(node->client) == ws) - if(i-- == nindex) - return node->client; - + for(tags = t; *tags; tags++) + if(is_client_tagged(node->client, *tags)) + if(i-- == nindex) + return node->client; return NULL; } -/** Get the latest focused client on a workspace. - * \param ws The workspace. +/** Get the latest focused client on a screen. + * \param screen The virtual screen number. * \return A pointer to an existing client. */ client_t * -focus_client_getcurrent(workspace_t *ws) +focus_get_current_client(int screen) { - return focus_get_latest_client_for_workspace(ws, 0); + tag_t **curtags = tags_get_current(screen); + client_t *sel = focus_get_latest_client_for_tags(curtags, 0); + p_delete(&curtags); + + return sel; } // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/focus.h b/focus.h index b233b6297..2662d16d9 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_client_getcurrent(workspace_t *); +client_t * focus_get_current_client(int); #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 f271a429e..84da94cb8 100644 --- a/layout.c +++ b/layout.c @@ -23,12 +23,13 @@ #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 "workspace.h" +#include "layouts/magnifier.h" #include "layouts/tile.h" #include "layouts/max.h" #include "layouts/fibonacci.h" @@ -36,27 +37,26 @@ extern awesome_t globalconf; -/** Arrange windows following current selected layout. - * \param ws The workspace to arrange. +/** Arrange windows following current selected layout + * \param screen the screen to arrange */ static void -arrange(workspace_t *ws) +arrange(int screen) { client_t *c; - int fscreen, screen = workspace_screen_get(ws), phys_screen = screen_virttophys(screen); + layout_t *curlay = layout_get_current(screen); + int fscreen, phys_screen = screen_virttophys(screen); xcb_query_pointer_cookie_t qp_c; xcb_query_pointer_reply_t *qp_r; - workspace_t *cws; for(c = globalconf.clients; c; c = c->next) - if((cws = workspace_client_get(c)) == ws && !c->ishidden) - { - screen_client_moveto(c, screen); + { + if(!c->ishidden && client_isvisible(c, screen)) client_unban(c); - } /* we don't touch other screens windows */ - else if(c->ishidden || workspace_screen_get(cws) == -1) + else if(c->screen == screen) client_ban(c); + } qp_c = xcb_query_pointer_unchecked(globalconf.connection, xcb_aux_get_screen(globalconf.connection, @@ -81,25 +81,26 @@ arrange(workspace_t *ws) /* if the mouse in on the same screen we just rearranged, and no * client are currently focused, pick the first one in history */ if(fscreen == screen - && (c = focus_client_getcurrent(ws))) - client_focus(c); + && (c = focus_get_current_client(screen))) + client_focus(c, screen); } p_delete(&qp_r); } - if(ws->layout) - ws->layout(ws); + if(curlay) + curlay(screen); /* reset status */ - ws->need_arrange = false; + globalconf.screens[screen].need_arrange = false; /* call hook */ - luaA_workspace_userdata_new(ws); + lua_pushnumber(globalconf.L, screen + 1); luaA_dofunction(globalconf.L, globalconf.hooks.arrange, 1); } -/** Refresh the screens disposition. +/** Refresh the screen disposition + * \return true if the screen was arranged, false otherwise */ void layout_refresh(void) @@ -107,8 +108,25 @@ layout_refresh(void) int screen; for(screen = 0; screen < globalconf.screens_info->nscreen; screen++) - if(globalconf.screens[screen].workspace && globalconf.screens[screen].workspace->need_arrange) - arrange(globalconf.screens[screen].workspace); + 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; } // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/layout.h b/layout.h index 61612623d..2ceffb459 100644 --- a/layout.h +++ b/layout.h @@ -25,6 +25,9 @@ #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 04f311d79..6b3b2c768 100644 --- a/layouts/fibonacci.c +++ b/layouts/fibonacci.c @@ -20,19 +20,18 @@ */ #include "screen.h" -#include "workspace.h" +#include "tag.h" #include "client.h" #include "layouts/fibonacci.h" extern awesome_t globalconf; static void -layout_fibonacci(workspace_t *ws, int shape) +layout_fibonacci(int screen, 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); @@ -89,15 +88,15 @@ layout_fibonacci(workspace_t *ws, int shape) } void -layout_spiral(workspace_t *ws) +layout_spiral(int screen) { - layout_fibonacci(ws, 0); + layout_fibonacci(screen, 0); } void -layout_dwindle(workspace_t *ws) +layout_dwindle(int screen) { - layout_fibonacci(ws, 1); + layout_fibonacci(screen, 1); } // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/layouts/floating.c b/layouts/floating.c index 13b6eda8f..678149bd6 100644 --- a/layouts/floating.c +++ b/layouts/floating.c @@ -20,16 +20,15 @@ */ #include "client.h" -#include "workspace.h" +#include "tag.h" #include "layouts/floating.h" extern awesome_t globalconf; void -layout_floating(workspace_t *ws) +layout_floating(int screen) { 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 a78a260b8..f76e3851f 100644 --- a/layouts/magnifier.c +++ b/layouts/magnifier.c @@ -20,7 +20,7 @@ */ #include "client.h" -#include "workspace.h" +#include "tag.h" #include "screen.h" #include "focus.h" #include "layouts/magnifier.h" @@ -28,16 +28,16 @@ extern awesome_t globalconf; void -layout_magnifier(workspace_t *ws) +layout_magnifier(int screen) { int n = 0; client_t *c, *focus; - int screen = workspace_screen_get(ws); + tag_t **curtags = tags_get_current(screen); area_t geometry, area = screen_area_get(screen, globalconf.screens[screen].statusbar, &globalconf.screens[screen].padding); - focus = focus_client_getcurrent(ws); + focus = focus_get_current_client(screen); /* If focused window is not tiled, take the first one which is tiled. */ if(!IS_TILED(focus, screen)) @@ -45,10 +45,10 @@ layout_magnifier(workspace_t *ws) /* No windows is tiled, nothing to do. */ if(!focus) - return; + goto bailout; - geometry.width = area.width * ws->mwfact; - geometry.height = area.height * ws->mwfact; + geometry.width = area.width * curtags[0]->mwfact; + geometry.height = area.height * curtags[0]->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(workspace_t *ws) /* No other clients. */ if(!n) - return; + goto bailout; geometry.x = area.x; geometry.y = area.y; @@ -81,5 +81,8 @@ layout_magnifier(workspace_t *ws) 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 8737164ec..fd71f930e 100644 --- a/layouts/max.c +++ b/layouts/max.c @@ -19,7 +19,7 @@ * */ -#include "workspace.h" +#include "tag.h" #include "screen.h" #include "client.h" #include "focus.h" @@ -28,13 +28,12 @@ extern awesome_t globalconf; void -layout_max(workspace_t *ws) +layout_max(int screen) { 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)) @@ -46,7 +45,7 @@ layout_max(workspace_t *ws) area.height += 2 * c->border; } - if((focus = focus_client_getcurrent(ws)) + if((focus = focus_get_current_client(screen)) && IS_TILED(focus, screen)) client_raise(focus); } diff --git a/layouts/tile.c b/layouts/tile.c index 342ee0019..c15771ade 100644 --- a/layouts/tile.c +++ b/layouts/tile.c @@ -22,7 +22,7 @@ #include <stdio.h> #include "screen.h" -#include "workspace.h" +#include "tag.h" #include "client.h" #include "layouts/tile.h" #include "common/util.h" @@ -30,18 +30,17 @@ extern awesome_t globalconf; static void -_tile(workspace_t *ws, const position_t position) +_tile(int screen, 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 screen, real_ncol = 1, win_by_col = 1, current_col = 0; + int real_ncol = 1, win_by_col = 1, current_col = 0; area_t area, geometry = { 0, 0, 0, 0, NULL, NULL }; client_t *c; - - screen = workspace_screen_get(ws); + tag_t **curtags = tags_get_current(screen); area = screen_area_get(screen, globalconf.screens[screen].statusbar, @@ -56,34 +55,34 @@ _tile(workspace_t *ws, const position_t position) wax = area.x; way = area.y; - masterwin = MIN(n, ws->nmaster); + masterwin = MIN(n, curtags[0]->nmaster); otherwin = MAX(n - masterwin, 0); - if(ws->nmaster) + if(curtags[0]->nmaster) switch(position) { case Right: case Left: mh = masterwin ? wah / masterwin : wah; - mw = otherwin ? waw * ws->mwfact : waw; + mw = otherwin ? waw * curtags[0]->mwfact : waw; break; default: - mh = otherwin ? wah * ws->mwfact : wah; + mh = otherwin ? wah * curtags[0]->mwfact : wah; mw = masterwin ? waw / masterwin : waw; break; } else mh = mw = 0; - real_ncol = ws->ncol > 0 ? MIN(otherwin, ws->ncol) : MIN(otherwin, 1); + real_ncol = curtags[0]->ncol > 0 ? MIN(otherwin, curtags[0]->ncol) : MIN(otherwin, 1); for(i = 0, c = globalconf.clients; c; c = c->next) { if(!IS_TILED(c, screen)) continue; - if(i < ws->nmaster) + if(i < curtags[0]->nmaster) { switch(position) { @@ -117,8 +116,8 @@ _tile(workspace_t *ws, const position_t position) if(real_ncol) win_by_col = otherwin / real_ncol; - if((i - ws->nmaster) - && (i - ws->nmaster) % win_by_col == 0 + if((i - curtags[0]->nmaster) + && (i - curtags[0]->nmaster) % win_by_col == 0 && current_col < real_ncol - 1) current_col++; @@ -134,10 +133,10 @@ _tile(workspace_t *ws, const position_t position) geometry.width = (waw - mw) / real_ncol - 2 * c->border; - if(i == ws->nmaster || otherwin <= real_ncol || (i - ws->nmaster) % win_by_col == 0) + if(i == curtags[0]->nmaster || otherwin <= real_ncol || (i - curtags[0]->nmaster) % win_by_col == 0) geometry.y = way; else - geometry.y = way + ((i - ws->nmaster) % win_by_col) * (geometry.height + 2 * c->border); + geometry.y = way + ((i - curtags[0]->nmaster) % win_by_col) * (geometry.height + 2 * c->border); geometry.x = wax + current_col * (geometry.width + 2 * c->border); @@ -153,10 +152,10 @@ _tile(workspace_t *ws, const position_t position) geometry.height = (wah - mh) / real_ncol - 2 * c->border; - if(i == ws->nmaster || otherwin <= real_ncol || (i - ws->nmaster) % win_by_col == 0) + if(i == curtags[0]->nmaster || otherwin <= real_ncol || (i - curtags[0]->nmaster) % win_by_col == 0) geometry.x = wax; else - geometry.x = wax + ((i - ws->nmaster) % win_by_col) * (geometry.width + 2 * c->border); + geometry.x = wax + ((i - curtags[0]->nmaster) % win_by_col) * (geometry.width + 2 * c->border); geometry.y = way + current_col * (geometry.height + 2 * c->border); @@ -167,30 +166,32 @@ _tile(workspace_t *ws, const position_t position) } i++; } + + p_delete(&curtags); } void -layout_tile(workspace_t *ws) +layout_tile(int screen) { - _tile(ws, Right); + _tile(screen, Right); } void -layout_tileleft(workspace_t *ws) +layout_tileleft(int screen) { - _tile(ws, Left); + _tile(screen, Left); } void -layout_tilebottom(workspace_t *ws) +layout_tilebottom(int screen) { - _tile(ws, Bottom); + _tile(screen, Bottom); } void -layout_tiletop(workspace_t *ws) +layout_tiletop(int screen) { - _tile(ws, Top); + _tile(screen, Top); } // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/lua.c b/lua.c index 389ef06d4..65ab2d881 100644 --- a/lua.c +++ b/lua.c @@ -32,7 +32,7 @@ #include "config.h" #include "structs.h" #include "lua.h" -#include "workspace.h" +#include "tag.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_workspace_methods[]; -extern const struct luaL_reg awesome_workspace_meta[]; +extern const struct luaL_reg awesome_tag_methods[]; +extern const struct luaL_reg awesome_tag_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,17 +191,16 @@ luaA_screen_count(lua_State *L) return 1; } -/** Get the workspace displayed on a screen. - * \param A screen number. -*/ +/** Give the focus to a screen. + * \param A screen number + */ static int -luaA_screen_workspace_get(lua_State *L) +luaA_screen_focus(lua_State *L) { /* Our table begin at 0, Lua begins at 1 */ int screen = luaL_checknumber(L, 1) - 1; luaA_checkscreen(screen); - if(globalconf.screens[screen].workspace) - return luaA_workspace_userdata_new(globalconf.screens[screen].workspace); + client_focus(NULL, screen); return 0; } @@ -427,7 +426,7 @@ luaA_init(void) { { "coords_get", luaA_screen_coords_get }, { "count", luaA_screen_count }, - { "workspace_get", luaA_screen_workspace_get }, + { "focus", luaA_screen_focus }, { NULL, NULL } }; static const struct luaL_reg awesome_hooks_lib[] = @@ -459,8 +458,8 @@ luaA_init(void) /* Export hooks lib */ luaL_register(L, "mouse", awesome_mouse_lib); - /* Export workspace */ - luaA_openlib(L, "workspace", awesome_workspace_methods, awesome_workspace_meta); + /* Export tag */ + luaA_openlib(L, "tag", awesome_tag_methods, awesome_tag_meta); /* Export statusbar */ luaA_openlib(L, "statusbar", awesome_statusbar_methods, awesome_statusbar_meta); @@ -492,13 +491,18 @@ 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; } - /* \todo Assure there's at least one workspace */ + /* Assure there's at least one tag */ + for(screen = 0; screen < globalconf.screens_info->nscreen; screen++) + if(!globalconf.screens[screen].tags) + tag_append_to_screen(tag_new("default", layout_tile, 0.5, 1, 0), screen); return true; } diff --git a/mouse.c b/mouse.c index 051d7014e..4d83ccfa3 100644 --- a/mouse.c +++ b/mouse.c @@ -27,7 +27,7 @@ #include "mouse.h" #include "screen.h" -#include "workspace.h" +#include "tag.h" #include "event.h" #include "client.h" #include "titlebar.h" @@ -126,12 +126,11 @@ 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(screen, - globalconf.screens[screen].statusbar, - &globalconf.screens[screen].padding); + screen_area_get(c->screen, + globalconf.screens[c->screen].statusbar, + &globalconf.screens[c->screen].padding); geometry = titlebar_geometry_add(c->titlebar, geometry); geometry.width += 2 * c->border; @@ -141,7 +140,7 @@ mouse_snapclient(client_t *c, area_t geometry, int snap) mouse_snapclienttogeometry_inside(geometry, screen_geometry, snap); for(snapper = globalconf.clients; snapper; snapper = snapper->next) - if(snapper != c && client_isvisible(c, screen)) + if(snapper != c && client_isvisible(c, c->screen)) { snapper_geometry = snapper->geometry; snapper_geometry.width += 2 * c->border; @@ -297,9 +296,10 @@ 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; - workspace_t *ws = workspace_client_get(c); + layout_t *layout; 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,16 +334,18 @@ mouse_client_move(client_t *c, int snap) query_pointer_r = xcb_query_pointer_reply(globalconf.connection, query_pointer_c, NULL); - if(c->isfloating || ws->layout == layout_floating) + if(c->isfloating || layout == layout_floating) { sw = mouse_resizebar_new(c->phys_screen, c->border, c->geometry, &ctx); 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: @@ -357,7 +359,7 @@ mouse_client_move(client_t *c, int snap) p_delete(&ev); return; case XCB_MOTION_NOTIFY: - if(c->isfloating || ws->layout == layout_floating) + if(c->isfloating || layout == layout_floating) { ev_motion = (xcb_motion_notify_event_t *) ev; @@ -365,21 +367,6 @@ mouse_client_move(client_t *c, int snap) geometry.y = ocy + (ev_motion->event_y - query_pointer_r->root_y); geometry = mouse_snapclient(c, geometry, snap); - if((newscreen = screen_get_bycoord(globalconf.screens_info, screen, - geometry.x, geometry.y)) != screen) - { - if((ws = globalconf.screens[newscreen].workspace)) - { - screen = workspace_screen_get(ws); - workspace_client_set(c, ws); - } - else - { - p_delete(&ev); - break; - } - } - c->ismoving = true; client_resize(c, geometry, false); c->ismoving = false; @@ -393,24 +380,20 @@ mouse_client_move(client_t *c, int snap) { query_pointer_c = xcb_query_pointer_unchecked(globalconf.connection, s->root); mquery_pointer_r = xcb_query_pointer_reply(globalconf.connection, query_pointer_c, NULL); - if((newscreen = screen_get_bycoord(globalconf.screens_info, - screen, + if((newscreen = screen_get_bycoord(globalconf.screens_info, c->screen, mquery_pointer_r->root_x, - mquery_pointer_r->root_y)) != screen - && globalconf.screens[newscreen].workspace) + mquery_pointer_r->root_y)) != c->screen) { - ws->need_arrange = true; - ws = globalconf.screens[newscreen].workspace; - screen = workspace_screen_get(ws); - workspace_client_set(c, ws); - ws->need_arrange = true; + screen_client_moveto(c, newscreen, true); + globalconf.screens[c->screen].need_arrange = true; + globalconf.screens[newscreen].need_arrange = true; layout_refresh(); } if((target = client_getbywin(mquery_pointer_r->child)) && target != c && !target->isfloating) { client_list_swap(&globalconf.clients, c, target); - ws->need_arrange = true; + globalconf.screens[c->screen].need_arrange = true; layout_refresh(); } p_delete(&mquery_pointer_r); @@ -425,6 +408,8 @@ mouse_client_move(client_t *c, int snap) p_delete(&ev); break; } + } + } } @@ -592,57 +577,62 @@ 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 workspace/layout to resize. + * \param c A client on the tag/layout to resize. */ static void mouse_client_resize_tiled(client_t *c) { - xcb_screen_t *xscreen; + xcb_screen_t *screen; /* screen area modulo statusbar */ area_t area; - /* current workspace */ - workspace_t *ws = workspace_client_get(c); - int mouse_x, mouse_y, screen = workspace_screen_get(ws); + /* current tag */ + tag_t *tag; + /* current layout */ + layout_t *layout; + + int mouse_x, mouse_y; size_t cursor = CurResize; - xscreen = xcb_aux_get_screen(globalconf.connection, c->phys_screen); + screen = xcb_aux_get_screen(globalconf.connection, c->phys_screen); + tag = tags_get_current(c->screen)[0]; + layout = tag->layout; - area = screen_area_get(screen, - globalconf.screens[screen].statusbar, - &globalconf.screens[screen].padding); + area = screen_area_get(tag->screen, + globalconf.screens[tag->screen].statusbar, + &globalconf.screens[tag->screen].padding); - mouse_query_pointer(xscreen->root, &mouse_x, &mouse_y); + mouse_query_pointer(screen->root, &mouse_x, &mouse_y); /* select initial pointer position */ - if(ws->layout == layout_tile) + if(layout == layout_tile) { - mouse_x = area.x + area.width * ws->mwfact; + mouse_x = area.x + area.width * tag->mwfact; cursor = CurResizeH; } - else if(ws->layout == layout_tileleft) + else if(layout == layout_tileleft) { - mouse_x = area.x + area.width * (1. - ws->mwfact); + mouse_x = area.x + area.width * (1. - tag->mwfact); cursor = CurResizeH; } - else if(ws->layout == layout_tilebottom) + else if(layout == layout_tilebottom) { - mouse_y = area.y + area.height * ws->mwfact; + mouse_y = area.y + area.height * tag->mwfact; cursor = CurResizeV; } - else if(ws->layout == layout_tiletop) + else if(layout == layout_tiletop) { - mouse_y = area.y + area.height * (1. - ws->mwfact); + mouse_y = area.y + area.height * (1. - tag->mwfact); cursor = CurResizeV; } else return; /* grab the pointer */ - if(!mouse_grab_pointer(xscreen->root, cursor)) + if(!mouse_grab_pointer(screen->root, cursor)) return; /* set pointer to the moveable border */ - mouse_warp_pointer(xscreen->root, mouse_x, mouse_y); + mouse_warp_pointer(screen->root, mouse_x, mouse_y); xcb_aux_sync(globalconf.connection); @@ -655,20 +645,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(ws->layout == layout_tile) + if(layout == layout_tile) mwfact = fact_x; - else if(ws->layout == layout_tileleft) + else if(layout == layout_tileleft) mwfact = 1. - fact_x; - else if(ws->layout == layout_tilebottom) + else if(layout == layout_tilebottom) mwfact = fact_y; - else if(ws->layout == layout_tiletop) + else if(layout == layout_tiletop) mwfact = 1. - fact_y; /* refresh layout */ - if(fabs(ws->mwfact - mwfact) >= 0.01) + if(fabs(tag->mwfact - mwfact) >= 0.01) { - ws->mwfact = mwfact; - ws->need_arrange = true; + tag->mwfact = mwfact; + globalconf.screens[tag->screen].need_arrange = true; layout_refresh(); xcb_aux_sync(globalconf.connection); } @@ -689,13 +679,16 @@ static void mouse_client_resize(client_t *c, corner_t corner) { int n, screen; - workspace_t *ws = workspace_client_get(c); + tag_t **curtags; + layout_t *layout; 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(ws->layout == layout_floating || c->isfloating) + if(layout == layout_floating || c->isfloating) { if(c->isfixed) return; @@ -704,16 +697,16 @@ mouse_client_resize(client_t *c, corner_t corner) mouse_client_resize_floating(c, corner); } - else if (ws->layout == layout_tile || ws->layout == layout_tileleft - || ws->layout == layout_tilebottom || ws->layout == layout_tiletop) + else if (layout == layout_tile || layout == layout_tileleft + || layout == layout_tilebottom || layout == layout_tiletop) { - screen = workspace_screen_get(ws); + screen = c->screen; for(n = 0, c = globalconf.clients; c; c = c->next) if(IS_TILED(c, screen)) n++; /* only masters on this screen? */ - if(n <= ws->nmaster) return; + if(n <= curtags[0]->nmaster) return; /* no tiled clients on this screen? */ for(c = globalconf.clients; c && !IS_TILED(c, screen); c = c->next); @@ -786,8 +779,8 @@ static int luaA_mouse_screen_get(lua_State *L) { int screen; - xcb_query_pointer_cookie_t qc; - xcb_query_pointer_reply_t *qr; + xcb_query_pointer_cookie_t qc; + xcb_query_pointer_reply_t *qr; qc = xcb_query_pointer(globalconf.connection, xcb_aux_get_screen(globalconf.connection, diff --git a/placement.c b/placement.c index 0a40973a8..5ee5c8434 100644 --- a/placement.c +++ b/placement.c @@ -26,7 +26,6 @@ #include "screen.h" #include "client.h" #include "titlebar.h" -#include "workspace.h" #include "layouts/floating.h" extern awesome_t globalconf; @@ -72,21 +71,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; - workspace_t *ws = workspace_client_get(c); - int screen = workspace_screen_get(ws); + layout_t *layout; screen_geometry = p_new(area_t, 1); - *screen_geometry = screen_area_get(screen, - globalconf.screens[screen].statusbar, - &globalconf.screens[screen].padding); + *screen_geometry = screen_area_get(c->screen, + globalconf.screens[c->screen].statusbar, + &globalconf.screens[c->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 || ws->layout == layout_floating) - && client_isvisible(client, screen)) + if((client->isfloating || layout == layout_floating) + && client_isvisible(client, c->screen)) { newgeometry = client->f_geometry; newgeometry.width += 2 * client->border; @@ -120,7 +119,7 @@ placement_smart(client_t *c) newgeometry.height = c->f_geometry.height; newgeometry = titlebar_geometry_add(c->titlebar, newgeometry); - newgeometry = placement_fix_offscreen(newgeometry, screen, c->border); + newgeometry = placement_fix_offscreen(newgeometry, c->screen, c->border); newgeometry = titlebar_geometry_remove(c->titlebar, newgeometry); area_list_wipe(&arealist); @@ -134,7 +133,6 @@ 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); @@ -147,7 +145,7 @@ placement_under_mouse(client_t *c) } finalgeometry = titlebar_geometry_add(c->titlebar, finalgeometry); - finalgeometry = placement_fix_offscreen(finalgeometry, screen, c->border); + finalgeometry = placement_fix_offscreen(finalgeometry, c->screen, c->border); finalgeometry = titlebar_geometry_remove(c->titlebar, finalgeometry); return finalgeometry; diff --git a/screen.c b/screen.c index a2a570317..dbec291b5 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,80 +121,93 @@ screen_virttophys(int screen) /** Move a client to a virtual screen. * \param c The client to move. - * \param new_screen The new screen. + * \param new_screen The destinatiuon screen number. + * \param doresize Set to true if we also move the client to the new x and + * y of the new screen. */ void -screen_client_moveto(client_t *c, int new_screen) +screen_client_moveto(client_t *c, int new_screen, bool doresize) { - area_t from, to, new_geometry, new_f_geometry; - int old_screen; + tag_t *tag; + int old_screen = c->screen; + area_t from, to; - old_screen = screen_get_bycoord(globalconf.screens_info, c->phys_screen, - c->geometry.x, c->geometry.y); + for(tag = globalconf.screens[old_screen].tags; tag; tag = tag->next) + untag_client(c, tag); - /* nothing to do */ - if(old_screen == new_screen) - return; + c->screen = new_screen; - new_f_geometry = c->f_geometry; + /* tag client with new screen tags */ + tag_client_with_current_selected(c); - 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) + /* resize the windows if it's floating */ + if(doresize && old_screen != c->screen) { - new_geometry = c->geometry; + 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); /* 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; + 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_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(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; - /* 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; + if(c->ismax) + { + new_geometry = c->geometry; - /* 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; + /* 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; - client_resize(c, new_geometry, false); + /* 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; + } } - /* 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 71dc8f45b..ff132db9b 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); +void screen_client_moveto(client_t *, int, bool); #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 e99b3db2f..dcafed3e3 100644 --- a/statusbar.c +++ b/statusbar.c @@ -24,6 +24,7 @@ #include "statusbar.h" #include "screen.h" +#include "tag.h" #include "widget.h" #include "window.h" @@ -79,8 +80,7 @@ statusbar_position_update(statusbar_t *statusbar, position_t position) xcb_screen_t *s = NULL; bool ignore = false; - if(globalconf.screens[statusbar->screen].workspace) - globalconf.screens[statusbar->screen].workspace->need_arrange = true; + globalconf.screens[statusbar->screen].need_arrange = true; simplewindow_delete(&statusbar->sw); draw_context_delete(&statusbar->ctx); @@ -412,8 +412,7 @@ luaA_statusbar_remove(lua_State *L) statusbar_position_update(*sb, Off); statusbar_list_detach(&globalconf.screens[i].statusbar, *sb); statusbar_unref(sb); - if(globalconf.screens[s->screen].workspace) - globalconf.screens[s->screen].workspace->need_arrange = true; + globalconf.screens[i].need_arrange = true; return 0; } diff --git a/structs.h b/structs.h index c723532f9..6ca0f2030 100644 --- a/structs.h +++ b/structs.h @@ -50,8 +50,6 @@ 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; @@ -60,7 +58,8 @@ 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 workspace_client_node_t workspace_client_node_t; +typedef struct _tag_t tag_t; +typedef struct tag_client_node_t tag_client_node_t; typedef area_t (FloatingPlacement)(client_t *); typedef struct awesome_t awesome_t; @@ -280,6 +279,8 @@ struct client_t bool skiptb; /** Window of the client */ xcb_window_t win; + /** Client logical screen */ + int screen; /** Client physical screen */ int phys_screen; /** Layer in the stacking order */ @@ -300,14 +301,18 @@ struct client_node_t client_node_t *prev, *next; }; -/** Workspace type */ -struct workspace_t +/** Tag type */ +struct _tag_t { /** Ref count */ int refcount; /** Tag name */ char *name; - /** Current workspace layout */ + /** Screen */ + int screen; + /** true if selected */ + bool selected; + /** Current tag layout */ layout_t *layout; /** Master width factor */ double mwfact; @@ -315,19 +320,17 @@ struct workspace_t int nmaster; /** Number of columns in tile layout */ int ncol; - /** True if we need to arrange() */ - bool need_arrange; - /** Next and previous workspaces */ - workspace_t *prev, *next; + /** Next and previous tags */ + tag_t *prev, *next; }; /** Tag client link type */ -struct workspace_client_node_t +struct tag_client_node_t { - workspace_t *workspace; + tag_t *tag; client_t *client; - /** Next and previous workspace_client_nodes */ - workspace_client_node_t *prev, *next; + /** Next and previous tag_client_nodes */ + tag_client_node_t *prev, *next; }; /** Padding type */ @@ -343,15 +346,16 @@ 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 */ @@ -400,8 +404,8 @@ struct awesome_t client_node_t *focus; /** Stack client history */ client_node_t *stack; - /** Link between workspaces and clients */ - workspace_client_node_t *wclink; + /** Link between tags and clients */ + tag_client_node_t *tclink; /** Command line passed to awesome */ char *argv; /** Last XMotionEvent coords */ @@ -440,8 +444,6 @@ 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 new file mode 100644 index 000000000..5550f41b0 --- /dev/null +++ b/tag.c @@ -0,0 +1,564 @@ +/* + * tag.c - tag management + * + * Copyright © 2007-2008 Julien Danjou <julien@danjou.info> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <stdio.h> +#include <X11/Xutil.h> + +#include "screen.h" +#include "tag.h" +#include "client.h" +#include "ewmh.h" +#include "widget.h" + +#include "layouts/magnifier.h" +#include "layouts/tile.h" +#include "layouts/max.h" +#include "layouts/floating.h" +#include "layouts/fibonacci.h" + +#include "layoutgen.h" + +extern awesome_t globalconf; + +/** View or unview a tag. + * \param tag the tag + * \param view set visible or not + */ +static void +tag_view(tag_t *tag, bool view) +{ + tag->selected = view; + ewmh_update_net_current_desktop(screen_virttophys(tag->screen)); + widget_invalidate_cache(tag->screen, WIDGET_CACHE_TAGS); + globalconf.screens[tag->screen].need_arrange = true; +} + +/** Create a new tag. Parameteres values are checked. + * \param name tag name + * \param layout layout to use + * \param mwfact master width factor + * \param nmaster number of master windows + * \param ncol number of columns for slaves windows + * \return a new tag with all these parameters + */ +tag_t * +tag_new(const char *name, layout_t *layout, double mwfact, int nmaster, int ncol) +{ + tag_t *tag; + + tag = p_new(tag_t, 1); + tag->name = a_strdup(name); + tag->layout = layout; + + tag->mwfact = mwfact; + if(tag->mwfact <= 0 || tag->mwfact >= 1) + tag->mwfact = 0.5; + + if((tag->nmaster = nmaster) < 0) + tag->nmaster = 1; + + if((tag->ncol = ncol) < 1) + tag->ncol = 1; + + return tag; +} + +/** Append a tag to a screen. + * \param tag the tag to append + * \param screen the screen id + */ +void +tag_append_to_screen(tag_t *tag, int screen) +{ + int phys_screen = screen_virttophys(screen); + + tag->screen = screen; + tag_list_append(&globalconf.screens[screen].tags, tag); + tag_ref(&tag); + ewmh_update_net_numbers_of_desktop(phys_screen); + ewmh_update_net_desktop_names(phys_screen); + widget_invalidate_cache(screen, WIDGET_CACHE_TAGS); +} + +/** Tag a client with specified tag. + * \param c the client to tag + * \param t the tag to tag the client with + */ +void +tag_client(client_t *c, tag_t *t) +{ + tag_client_node_t *tc; + + /* don't tag twice */ + if(is_client_tagged(c, t)) + return; + + tc = p_new(tag_client_node_t, 1); + tc->client = c; + tc->tag = t; + tag_client_node_list_push(&globalconf.tclink, tc); + + client_saveprops(c); + widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); + globalconf.screens[c->screen].need_arrange = true; +} + +/** Untag a client with specified tag. + * \param c the client to tag + * \param t the tag to tag the client with + */ +void +untag_client(client_t *c, tag_t *t) +{ + tag_client_node_t *tc; + + for(tc = globalconf.tclink; tc; tc = tc->next) + if(tc->client == c && tc->tag == t) + { + tag_client_node_list_detach(&globalconf.tclink, tc); + p_delete(&tc); + client_saveprops(c); + widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); + globalconf.screens[c->screen].need_arrange = True; + break; + } +} + +/** Check if a client is tagged with the specified tag. + * \param c the client + * \param t the tag + * \return true if the client is tagged with the tag, false otherwise. + */ +bool +is_client_tagged(client_t *c, tag_t *t) +{ + tag_client_node_t *tc; + + if(!c) + return false; + + for(tc = globalconf.tclink; tc; tc = tc->next) + if(tc->client == c && tc->tag == t) + return true; + + return false; +} + +/** Tag the client with the currently selected (visible) tags. + * \param c the client + */ +void +tag_client_with_current_selected(client_t *c) +{ + tag_t *tag; + screen_t vscreen = globalconf.screens[c->screen]; + + for(tag = vscreen.tags; tag; tag = tag->next) + if(tag->selected) + tag_client(c, tag); + else + untag_client(c, tag); +} + +/** Get the current tags for the specified screen. + * Returned pointer must be p_delete'd after. + * \param screen screen id + * \return a double pointer of tag list finished with a NULL element + */ +tag_t ** +tags_get_current(int screen) +{ + tag_t *tag, **tags = NULL; + int n = 1; + + tags = p_new(tag_t *, n); + for(tag = globalconf.screens[screen].tags; tag; tag = tag->next) + if(tag->selected) + { + p_realloc(&tags, ++n); + tags[n - 2] = tag; + } + + /* finish with null */ + tags[n - 1] = NULL; + + return tags; +} + + +/** Set a tag to be the only one viewed. + * \param target the tag to see + */ +static void +tag_view_only(tag_t *target) +{ + tag_t *tag; + + if(!target) return; + + for(tag = globalconf.screens[target->screen].tags; tag; tag = tag->next) + tag_view(tag, tag == target); +} + +/** View only a tag, selected by its index. + * \param screen screen id + * \param dindex the index + */ +void +tag_view_only_byindex(int screen, int dindex) +{ + tag_t *tag; + + if(dindex < 0) + return; + + for(tag = globalconf.screens[screen].tags; tag && dindex > 0; + tag = tag->next, dindex--); + tag_view_only(tag); +} + +/** Check for tag equality. + * \param Another tag. + * \return True if tags are equals. + */ +static int +luaA_tag_eq(lua_State *L) +{ + tag_t **t1 = luaA_checkudata(L, 1, "tag"); + tag_t **t2 = luaA_checkudata(L, 2, "tag"); + lua_pushboolean(L, (*t1 == *t2)); + return 1; +} + +/** Convert a tag to a printable string. + * \return A string. + */ +static int +luaA_tag_tostring(lua_State *L) +{ + tag_t **p = luaA_checkudata(L, 1, "tag"); + lua_pushfstring(L, "[tag udata(%p) name(%s)]", *p, (*p)->name); + return 1; +} + +/** Add a tag to a screen. + * \param A screen number. + */ +static int +luaA_tag_add(lua_State *L) +{ + tag_t *t, **tag = luaA_checkudata(L, 1, "tag"); + int i, screen = luaL_checknumber(L, 2) - 1; + luaA_checkscreen(screen); + + for(i = 0; i < globalconf.screens_info->nscreen; i++) + for(t = globalconf.screens[i].tags; t; t = t->next) + if(*tag == t) + luaL_error(L, "tag already on screen %d", i + 1); + + (*tag)->screen = screen; + tag_append_to_screen(*tag, screen); + return 0; +} + +/** Get all tags from a screen. + * \param A screen number. + * \return A table with all tags from the screen specified. + */ +static int +luaA_tag_get(lua_State *L) +{ + int screen = luaL_checknumber(L, 1) - 1; + tag_t *tag; + int i = 1; + + luaA_checkscreen(screen); + + lua_newtable(L); + + for(tag = globalconf.screens[screen].tags; tag; tag = tag->next) + { + luaA_tag_userdata_new(tag); + lua_rawseti(L, -2, i++); + } + + return 1; +} + +/** Create a new tag. + * \param A table with at least a name attribute. + * Optionnal attributes are: mwfact, ncol, nmaster and layout. + * \return A new tag object. + */ +static int +luaA_tag_new(lua_State *L) +{ + tag_t *tag; + int ncol, nmaster; + const char *name, *lay; + double mwfact; + layout_t *layout; + + luaA_checktable(L, 1); + + name = luaA_name_init(L); + mwfact = luaA_getopt_number(L, 1, "mwfact", 0.5); + ncol = luaA_getopt_number(L, 1, "ncol", 1); + nmaster = luaA_getopt_number(L, 1, "nmaster", 1); + lay = luaA_getopt_string(L, 1, "layout", "tile"); + + layout = name_func_lookup(lay, LayoutList); + + tag = tag_new(name, + layout, + mwfact, nmaster, ncol); + + return luaA_tag_userdata_new(tag); +} + +/** Add or remove a tag from the current view. + * \param A boolean value, true to view tag, false otherwise. + */ +static int +luaA_tag_view(lua_State *L) +{ + tag_t **tag = luaA_checkudata(L, 1, "tag"); + bool view = luaA_checkboolean(L, 2); + tag_view(*tag, view); + return 0; +} + +/** Get the tag selection attribute. + * \return True if the tag is viewed, false otherwise. + */ +static int +luaA_tag_isselected(lua_State *L) +{ + tag_t **tag = luaA_checkudata(L, 1, "tag"); + lua_pushboolean(L, (*tag)->selected); + return 1; +} + +/** Set the tag master width factor. This value is used in various layouts to + * determine the size of the master window. + * \param The master width ratio value, between 0 and 1. + */ +static int +luaA_tag_mwfact_set(lua_State *L) +{ + tag_t **tag = luaA_checkudata(L, 1, "tag"); + double mwfact = luaL_checknumber(L, 2); + + if(mwfact < 1 && mwfact > 0) + { + (*tag)->mwfact = mwfact; + globalconf.screens[(*tag)->screen].need_arrange = true; + } + else + luaL_error(L, "bad value, must be between 0 and 1"); + + return 0; +} + +/** Get the tag master width factor. + * \return The master width ratio value. + */ +static int +luaA_tag_mwfact_get(lua_State *L) +{ + tag_t **tag = luaA_checkudata(L, 1, "tag"); + lua_pushnumber(L, (*tag)->mwfact); + return 1; +} + +/** Set the number of columns. This is used in various layouts to set the number + * of columns used to display non-master windows. + * \param The number of columns, at least 1. + */ +static int +luaA_tag_ncol_set(lua_State *L) +{ + tag_t **tag = luaA_checkudata(L, 1, "tag"); + int ncol = luaL_checknumber(L, 2); + + if(ncol >= 1) + { + (*tag)->ncol = ncol; + globalconf.screens[(*tag)->screen].need_arrange = true; + } + else + luaL_error(L, "bad value, must be greater than 1"); + + return 0; +} + +/** Get the number of columns used to display non-master windows on this tag. + * \return The number of column. + */ +static int +luaA_tag_ncol_get(lua_State *L) +{ + tag_t **tag = luaA_checkudata(L, 1, "tag"); + lua_pushnumber(L, (*tag)->ncol); + return 1; +} + +/** Set the number of master windows. This is used in various layouts to + * determine how many windows are in the master area. + * \param The number of master windows. + */ +static int +luaA_tag_nmaster_set(lua_State *L) +{ + tag_t **tag = luaA_checkudata(L, 1, "tag"); + int nmaster = luaL_checknumber(L, 2); + + if(nmaster >= 0) + { + (*tag)->nmaster = nmaster; + globalconf.screens[(*tag)->screen].need_arrange = true; + } + else + luaL_error(L, "bad value, must be greater than 0"); + + return 0; +} + +/** Get the number of master windows of the tag. + * \return The number of master windows. + */ +static int +luaA_tag_nmaster_get(lua_State *L) +{ + tag_t **tag = luaA_checkudata(L, 1, "tag"); + lua_pushnumber(L, (*tag)->nmaster); + return 1; +} + +/** Get the tag name. + * \return The tag name. + */ +static int +luaA_tag_name_get(lua_State *L) +{ + tag_t **tag = luaA_checkudata(L, 1, "tag"); + lua_pushstring(L, (*tag)->name); + return 1; +} + +/** Set the tag name. + * \param A string with the new tag name. + */ +static int +luaA_tag_name_set(lua_State *L) +{ + tag_t **tag = luaA_checkudata(L, 1, "tag"); + const char *name = luaL_checkstring(L, 2); + p_delete(&(*tag)->name); + (*tag)->name = a_strdup(name); + return 0; +} + +/** Handle tag garbage collection. + */ +static int +luaA_tag_gc(lua_State *L) +{ + tag_t **tag = luaA_checkudata(L, 1, "tag"); + tag_unref(tag); + *tag = NULL; + return 0; +} + +/** Get the layout of the tag. + * \return The layout name. + */ +static int +luaA_tag_layout_get(lua_State *L) +{ + tag_t **tag = luaA_checkudata(L, 1, "tag"); + const char *name = a_strdup(name_func_rlookup((*tag)->layout, LayoutList)); + lua_pushstring(L, name); + return 1; +} + +/** Set the layout of the tag. + * \param A layout name. + */ +static int +luaA_tag_layout_set(lua_State *L) +{ + tag_t **tag = luaA_checkudata(L, 1, "tag"); + const char *name = luaL_checkstring(L, 2); + layout_t *l = name_func_lookup(name, LayoutList); + + if(l) + { + (*tag)->layout = l; + globalconf.screens[(*tag)->screen].need_arrange = true; + } + else + luaL_error(L, "unknown layout: %s", name); + + return 0; + +} + +/** Create a new userdata from a tag. + * \param t The tag. + * \return The luaA_settype returnn value. + */ +int +luaA_tag_userdata_new(tag_t *t) +{ + tag_t **lt = lua_newuserdata(globalconf.L, sizeof(tag_t *)); + *lt = t; + tag_ref(lt); + return luaA_settype(globalconf.L, "tag"); +} + +const struct luaL_reg awesome_tag_methods[] = +{ + { "new", luaA_tag_new }, + { "get", luaA_tag_get}, + { NULL, NULL } +}; +const struct luaL_reg awesome_tag_meta[] = +{ + { "add", luaA_tag_add }, + { "view", luaA_tag_view }, + { "isselected", luaA_tag_isselected }, + { "mwfact_set", luaA_tag_mwfact_set }, + { "mwfact_get", luaA_tag_mwfact_get }, + { "ncol_set", luaA_tag_ncol_set }, + { "ncol_get", luaA_tag_ncol_get }, + { "nmaster_set", luaA_tag_nmaster_set }, + { "nmaster_get", luaA_tag_nmaster_get }, + { "name_get", luaA_tag_name_get }, + { "name_set", luaA_tag_name_set }, + { "layout_get", luaA_tag_layout_get }, + { "layout_set", luaA_tag_layout_set }, + { "__eq", luaA_tag_eq }, + { "__gc", luaA_tag_gc }, + { "__tostring", luaA_tag_tostring }, + { NULL, NULL }, +}; +// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/workspace.h b/tag.h similarity index 63% rename from workspace.h rename to tag.h index 74b91df98..cde5759dc 100644 --- a/workspace.h +++ b/tag.h @@ -1,5 +1,5 @@ /* - * workspace.h - workspace management header + * tag.h - tag management header * * Copyright © 2007-2008 Julien Danjou <julien@danjou.info> * @@ -19,8 +19,8 @@ * */ -#ifndef AWESOME_WORKSPACE_H -#define AWESOME_WORKSPACE_H +#ifndef AWESOME_TAG_H +#define AWESOME_TAG_H #include "structs.h" #include "common/refcount.h" @@ -29,26 +29,28 @@ #define IS_TILED(client, screen) (client && !client->isfloating && !client->ismax && client_isvisible(client, screen)) /* Contructor, destructor and referencors */ -workspace_t * workspace_new(const char *, layout_t *, double, int, int); +tag_t * tag_new(const char *, layout_t *, double, int, int); static inline void -workspace_delete(workspace_t **workspace) +tag_delete(tag_t **tag) { - p_delete(&(*workspace)->name); - p_delete(workspace); + p_delete(&(*tag)->name); + p_delete(tag); } -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 *); +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 *); -int luaA_workspace_userdata_new(workspace_t *); +DO_RCNT(tag_t, tag, tag_delete) +DO_SLIST(tag_t, tag, tag_delete) -DO_RCNT(workspace_t, workspace, workspace_delete) -DO_SLIST(workspace_t, workspace, workspace_delete) - -DO_SLIST(workspace_client_node_t, workspace_client_node, p_delete) +DO_SLIST(tag_client_node_t, tag_client_node, p_delete) #endif // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/titlebar.c b/titlebar.c index e05303613..324e2db1a 100644 --- a/titlebar.c +++ b/titlebar.c @@ -28,7 +28,6 @@ #include "client.h" #include "screen.h" #include "widget.h" -#include "workspace.h" #include "layouts/floating.h" extern awesome_t globalconf; @@ -111,7 +110,7 @@ titlebar_draw(client_t *c) } widget_render(c->titlebar->widgets, ctx, c->titlebar->sw->gc, c->titlebar->sw->pixmap, - workspace_screen_get(workspace_client_get(c)), c->titlebar->position, + c->screen, c->titlebar->position, c->titlebar->sw->geometry.x, c->titlebar->sw->geometry.y, c->titlebar); switch(c->titlebar->position) diff --git a/widget.c b/widget.c index 751d34cf3..207292bc4 100644 --- a/widget.c +++ b/widget.c @@ -248,25 +248,24 @@ 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 flags) +widget_invalidate_cache(int screen, int flags) { statusbar_t *statusbar; widget_node_t *widget; - int screen; - 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; - } + 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 79ad42c07..c4746892a 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_WORKSPACES 1<<2 -#define WIDGET_CACHE_ALL (WIDGET_CACHE_CLIENTS | WIDGET_CACHE_LAYOUTS | WIDGET_CACHE_WORKSPACES) +#define WIDGET_CACHE_TAGS 1<<2 +#define WIDGET_CACHE_ALL (WIDGET_CACHE_CLIENTS | WIDGET_CACHE_LAYOUTS | WIDGET_CACHE_TAGS) typedef widget_t *(widget_constructor_t)(alignment_t); -void widget_invalidate_cache(int); +void widget_invalidate_cache(int, int); int widget_calculate_offset(int, int, int, int); 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 workspacelist_new; +widget_constructor_t taglist_new; widget_constructor_t textbox_new; widget_constructor_t iconbox_new; widget_constructor_t progressbar_new; diff --git a/widgets/workspacelist.c b/widgets/taglist.c similarity index 63% rename from widgets/workspacelist.c rename to widgets/taglist.c index 85ccc758a..b61875b35 100644 --- a/widgets/workspacelist.c +++ b/widgets/taglist.c @@ -1,7 +1,6 @@ /* - * workspacelist.c - workspace list widget + * taglist.c - tag list widget * - * Copyright © 2008 Julien Danjou <julien@danjou.info> * Copyright © 2007 Aldo Cortesi <aldo@nullcube.com> * * This program is free software; you can redistribute it and/or modify @@ -22,7 +21,7 @@ #include "client.h" #include "widget.h" -#include "workspace.h" +#include "tag.h" #include "lua.h" #include "event.h" #include "common/markup.h" @@ -30,26 +29,26 @@ extern awesome_t globalconf; -typedef struct workspacelist_drawn_area_t workspacelist_drawn_area_t; -struct workspacelist_drawn_area_t +typedef struct taglist_drawn_area_t taglist_drawn_area_t; +struct taglist_drawn_area_t { void *object; area_t *area; - workspacelist_drawn_area_t *next, *prev; + taglist_drawn_area_t *next, *prev; }; -DO_SLIST(workspacelist_drawn_area_t, workspacelist_drawn_area, p_delete); +DO_SLIST(taglist_drawn_area_t, taglist_drawn_area, p_delete); typedef struct { char *text_normal, *text_focus, *text_urgent; bool show_empty; - workspacelist_drawn_area_t *drawn_area; + taglist_drawn_area_t *drawn_area; -} workspacelist_data_t; +} taglist_data_t; static char * -workspace_markup_parse(workspace_t *t, const char *str, ssize_t len) +tag_markup_parse(tag_t *t, const char *str, ssize_t len) { const char *elements[] = { "title", NULL }; char *title_esc = g_markup_escape_text(t->name, -1); @@ -73,88 +72,89 @@ workspace_markup_parse(workspace_t *t, const char *str, ssize_t len) return ret; } -/** Check if at least one client is on the workspace. - * \param ws The workspace. - * \return True or false. +/** Check if at least one client is tagged with tag number t and is on screen + * screen + * \param t tag + * \return true or false */ static bool -workspace_isoccupied(workspace_t *ws) +tag_isoccupied(tag_t *t) { client_t *c; for(c = globalconf.clients; c; c = c->next) - if(workspace_client_get(c) == ws) + if(is_client_tagged(c, t) && !c->skip) return true; return false; } static bool -workspace_isurgent(workspace_t *ws) +tag_isurgent(tag_t *t) { client_t *c; for(c = globalconf.clients; c; c = c->next) - if(c->isurgent && workspace_client_get(c) == ws) + if(is_client_tagged(c, t) && c->isurgent) return true; return false; } static char * -workspacelist_text_get(workspace_t *ws, screen_t *screen, workspacelist_data_t *data) +taglist_text_get(tag_t *tag, taglist_data_t *data) { - if(screen->workspace == ws) + if(tag->selected) return data->text_focus; - - if(workspace_isurgent(ws)) + else if(tag_isurgent(tag)) return data->text_urgent; return data->text_normal; } static int -workspacelist_draw(draw_context_t *ctx, int screen, - widget_node_t *w, - int offset, - int used __attribute__ ((unused)), - void *object) +taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w, + int offset, + int used __attribute__ ((unused)), + void *object) { - workspace_t *ws; - workspacelist_data_t *data = w->widget->data; + tag_t *tag; + taglist_data_t *data = w->widget->data; + client_t *sel = globalconf.focus->client; + screen_t *vscreen = &globalconf.screens[screen]; int i = 0, prev_width = 0; area_t *area, rectangle = { 0, 0, 0, 0, NULL, NULL }; char **text = NULL; - workspacelist_drawn_area_t *tda; + taglist_drawn_area_t *tda; w->area.width = w->area.y = 0; - /* Lookup for our workspacelist_drawn_area. - * This will be used to store area where we draw ws list for each object. */ + /* Lookup for our taglist_drawn_area. + * This will be used to store area where we draw tag list for each object. */ for(tda = data->drawn_area; tda && tda->object != object; tda = tda->next); /* 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(workspacelist_drawn_area_t, 1); + tda = p_new(taglist_drawn_area_t, 1); tda->object = object; - workspacelist_drawn_area_list_push(&data->drawn_area, tda); + taglist_drawn_area_list_push(&data->drawn_area, tda); } area_list_wipe(&tda->area); /* First compute text and widget width */ - for(ws = globalconf.workspaces; ws; ws = ws->next, i++) + for(tag = vscreen->tags; tag; tag = tag->next, i++) { p_realloc(&text, i + 1); area = p_new(area_t, 1); - text[i] = workspacelist_text_get(ws, &globalconf.screens[screen], data); - text[i] = workspace_markup_parse(ws, text[i], a_strlen(text[i])); + text[i] = taglist_text_get(tag, data); + text[i] = tag_markup_parse(tag, text[i], a_strlen(text[i])); *area = draw_text_extents(ctx->connection, ctx->phys_screen, globalconf.font, text[i]); - if (data->show_empty || workspace_isoccupied(ws)) + if (data->show_empty || tag->selected || tag_isoccupied(tag)) w->area.width += area->width; area_list_append(&tda->area, area); @@ -164,11 +164,11 @@ workspacelist_draw(draw_context_t *ctx, int screen, w->area.x = widget_calculate_offset(ctx->width, w->area.width, offset, w->widget->align); - for(area = tda->area, ws = globalconf.workspaces, i = 0; - ws && area; - ws = ws->next, area = area->next, i++) + for(area = tda->area, tag = vscreen->tags, i = 0; + tag && area; + tag = tag->next, area = area->next, i++) { - if (!data->show_empty && !workspace_isoccupied(ws)) + if (!data->show_empty && !tag->selected && !tag_isoccupied(tag)) continue; area->x = w->area.x + prev_width; @@ -176,12 +176,13 @@ workspacelist_draw(draw_context_t *ctx, int screen, draw_text(ctx, globalconf.font, *area, text[i]); p_delete(&text[i]); - if(workspace_isoccupied(ws)) + if(tag_isoccupied(tag)) { rectangle.width = rectangle.height = (globalconf.font->height + 2) / 3; rectangle.x = area->x; rectangle.y = area->y; - draw_rectangle(ctx, rectangle, 1.0, false, ctx->fg); + draw_rectangle(ctx, rectangle, 1.0, + sel && is_client_tagged(sel, tag), ctx->fg); } } @@ -199,17 +200,18 @@ workspacelist_draw(draw_context_t *ctx, int screen, * \param type The type object. */ static void -workspacelist_button_press(widget_node_t *w, - xcb_button_press_event_t *ev, - int screen __attribute__ ((unused)), - void *object, - awesome_type_t type) +taglist_button_press(widget_node_t *w, + xcb_button_press_event_t *ev, + int screen, + void *object, + awesome_type_t type) { + screen_t *vscreen = &globalconf.screens[screen]; button_t *b; - workspacelist_data_t *data = w->widget->data; - workspacelist_drawn_area_t *tda; + taglist_data_t *data = w->widget->data; + taglist_drawn_area_t *tda; area_t *area; - workspace_t *ws; + tag_t *tag; /* Find the good drawn area list */ for(tda = data->drawn_area; tda && tda->object != object; tda = tda->next); @@ -217,22 +219,22 @@ workspacelist_button_press(widget_node_t *w, for(b = w->widget->buttons; b; b = b->next) if(ev->detail == b->button && CLEANMASK(ev->state) == b->mod && b->fct) - for(ws = globalconf.workspaces; ws && area; ws = ws->next, area = area->next) + for(tag = vscreen->tags; tag && area; tag = tag->next, area = area->next) if(ev->event_x >= AREA_LEFT(*area) && ev->event_x < AREA_RIGHT(*area) - && (data->show_empty || workspace_isoccupied(ws)) ) + && (data->show_empty || tag->selected || tag_isoccupied(tag)) ) { luaA_pushpointer(object, type); - luaA_workspace_userdata_new(ws); + luaA_tag_userdata_new(tag); luaA_dofunction(globalconf.L, b->fct, 2); return; } } static widget_tell_status_t -workspacelist_tell(widget_t *widget, const char *property, const char *new_value) +taglist_tell(widget_t *widget, const char *property, const char *new_value) { - workspacelist_data_t *d = widget->data; + taglist_data_t *d = widget->data; if(!a_strcmp(property, "text_normal")) { @@ -258,26 +260,26 @@ workspacelist_tell(widget_t *widget, const char *property, const char *new_value } widget_t * -workspacelist_new(alignment_t align) +taglist_new(alignment_t align) { widget_t *w; - workspacelist_data_t *d; + taglist_data_t *d; w = p_new(widget_t, 1); widget_common_new(w); w->align = align; - w->draw = workspacelist_draw; - w->button_press = workspacelist_button_press; - w->tell = workspacelist_tell; + w->draw = taglist_draw; + w->button_press = taglist_button_press; + w->tell = taglist_tell; - w->data = d = p_new(workspacelist_data_t, 1); + w->data = d = p_new(taglist_data_t, 1); d->text_normal = a_strdup(" <text align=\"center\"/><title/> "); d->text_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_WORKSPACES | WIDGET_CACHE_CLIENTS; + w->cache_flags = WIDGET_CACHE_TAGS | WIDGET_CACHE_CLIENTS; return w; } diff --git a/widgets/tasklist.c b/widgets/tasklist.c index 0ec282683..fbd99093f 100644 --- a/widgets/tasklist.c +++ b/widgets/tasklist.c @@ -25,6 +25,7 @@ #include "screen.h" #include "event.h" #include "ewmh.h" +#include "tag.h" #include "common/configopts.h" #include "common/markup.h" @@ -33,7 +34,7 @@ extern awesome_t globalconf; typedef enum { ShowFocus, - ShowWorkspace, + ShowTags, ShowAll, } showclient_t; @@ -53,11 +54,11 @@ tasklist_isvisible(client_t *c, int screen, showclient_t show) switch(show) { case ShowAll: - return true; - case ShowWorkspace: + return (c->screen == screen); + case ShowTags: return client_isvisible(c, screen); case ShowFocus: - return (c == focus_client_getcurrent(globalconf.screens[screen].workspace)); + return (c == focus_get_current_client(screen)); } return false; } @@ -262,8 +263,8 @@ tasklist_tell(widget_t *widget, const char *property, const char *new_value) d->show_icons = a_strtobool(new_value); else if(!a_strcmp(property, "show")) { - if(!a_strcmp(new_value, "workspace")) - d->show = ShowWorkspace; + if(!a_strcmp(new_value, "tags")) + d->show = ShowTags; else if(!a_strcmp(new_value, "focus")) d->show = ShowFocus; else if(!a_strcmp(new_value, "all")) @@ -295,7 +296,7 @@ tasklist_new(alignment_t align __attribute__ ((unused))) d->text_focus = a_strdup(" <title/> "); d->text_urgent = a_strdup(" <title/> "); d->show_icons = true; - d->show = ShowWorkspace; + d->show = ShowTags; /* Set cache property */ w->cache_flags = WIDGET_CACHE_CLIENTS; diff --git a/workspace.c b/workspace.c deleted file mode 100644 index 85f72de58..000000000 --- a/workspace.c +++ /dev/null @@ -1,515 +0,0 @@ -/* - * workspace.c - workspace management - * - * Copyright © 2007-2008 Julien Danjou <julien@danjou.info> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include "screen.h" -#include "workspace.h" -#include "client.h" -#include "ewmh.h" -#include "client.h" -#include "focus.h" -#include "widget.h" - -#include "layouts/magnifier.h" -#include "layouts/tile.h" -#include "layouts/max.h" -#include "layouts/floating.h" -#include "layouts/fibonacci.h" - -#include "layoutgen.h" - -extern awesome_t globalconf; - -/** View a workspace. - * \param workspace The workspace. - * \param screen The screen to view on. - */ -static void -workspace_view(workspace_t *workspace, int screen) -{ - int s; - - for(s = 0; s < globalconf.screens_info->nscreen; s++) - /* The workspace is already viewed on `s': switch */ - if(globalconf.screens[s].workspace == workspace) - { - globalconf.screens[s].workspace = globalconf.screens[screen].workspace; - globalconf.screens[s].workspace->need_arrange = true; - } - - ewmh_update_net_current_desktop(screen_virttophys(screen)); - widget_invalidate_cache(WIDGET_CACHE_WORKSPACES); - globalconf.screens[screen].workspace = workspace; - workspace->need_arrange = true; -} - -/** Get the display screen for a workspace. - * \param ws A workspace. - * \return A screen number. - */ -int -workspace_screen_get(workspace_t *ws) -{ - int screen = 0; - - for(; screen < globalconf.screens_info->nscreen; screen++) - if(globalconf.screens[screen].workspace == ws) - return screen; - return -1; -} - -/** Create a new workspace. Parameteres values are checked. - * \param name workspace name - * \param layout layout to use - * \param mwfact master width factor - * \param nmaster number of master windows - * \param ncol number of columns for slaves windows - * \return a new workspace with all these parameters - */ -workspace_t * -workspace_new(const char *name, layout_t *layout, double mwfact, int nmaster, int ncol) -{ - workspace_t *workspace; - - workspace = p_new(workspace_t, 1); - workspace->name = a_strdup(name); - workspace->layout = layout; - - workspace->mwfact = mwfact; - if(workspace->mwfact <= 0 || workspace->mwfact >= 1) - workspace->mwfact = 0.5; - - if((workspace->nmaster = nmaster) < 0) - workspace->nmaster = 1; - - if((workspace->ncol = ncol) < 1) - workspace->ncol = 1; - - return workspace; -} - -static workspace_client_node_t * -workspace_client_getnode(client_t *c) -{ - workspace_client_node_t *wc = NULL; - for(wc = globalconf.wclink; wc && wc->client != c; wc = wc->next); - return wc; -} - -workspace_t * -workspace_client_get(client_t *c) -{ - workspace_client_node_t *wc = workspace_client_getnode(c); - if(wc && wc->client == c) - return wc->workspace; - return NULL; -} - -/** Remove the client from its workspace. - * \param c The client - */ -void -workspace_client_remove(client_t *c) -{ - workspace_client_node_t *wc = workspace_client_getnode(c); - - if(wc && wc->client == c) - { - workspace_client_node_list_detach(&globalconf.wclink, wc); - client_saveprops(c); - widget_invalidate_cache(WIDGET_CACHE_CLIENTS); - wc->workspace->need_arrange = true; - p_delete(&wc); - } -} - -/** Put a client in the specified workspace. - * \param c The client. - * \param t The workspace. - */ -void -workspace_client_set(client_t *c, workspace_t *w) -{ - workspace_client_node_t *wc; - - if(!(wc = workspace_client_getnode(c))) - { - wc = p_new(workspace_client_node_t, 1); - wc->client = c; - workspace_client_node_list_push(&globalconf.wclink, wc); - } - wc->workspace = w; - client_saveprops(c); - widget_invalidate_cache(WIDGET_CACHE_CLIENTS); - w->need_arrange = true; -} - -/** Check for workspace equality. - * \param Another workspace. - * \return True if workspaces are equals. - */ -static int -luaA_workspace_eq(lua_State *L) -{ - workspace_t **t1 = luaA_checkudata(L, 1, "workspace"); - workspace_t **t2 = luaA_checkudata(L, 2, "workspace"); - lua_pushboolean(L, (*t1 == *t2)); - return 1; -} - -/** Convert a workspace to a printable string. - * \return A string. - */ -static int -luaA_workspace_tostring(lua_State *L) -{ - workspace_t **p = luaA_checkudata(L, 1, "workspace"); - lua_pushfstring(L, "[workspace udata(%p) name(%s)]", *p, (*p)->name); - return 1; -} - -/** Add a workspace. - */ -static int -luaA_workspace_add(lua_State *L) -{ - workspace_t *t, **workspace = luaA_checkudata(L, 1, "workspace"); - - for(t = globalconf.workspaces; t; t = t->next) - if(*workspace == t) - luaL_error(L, "workspace already added"); - - workspace_list_append(&globalconf.workspaces, *workspace); - workspace_ref(workspace); - /* \todo do it for all screens */ - ewmh_update_net_numbers_of_desktop(globalconf.default_screen); - ewmh_update_net_desktop_names(globalconf.default_screen); - widget_invalidate_cache(WIDGET_CACHE_WORKSPACES); - return 0; -} - -/** Get all workspaces. - * \return A table with all workspaces. - */ -static int -luaA_workspace_get(lua_State *L) -{ - workspace_t *workspace; - int i = 1; - - lua_newtable(L); - - for(workspace = globalconf.workspaces; workspace; workspace = workspace->next) - { - luaA_workspace_userdata_new(workspace); - lua_rawseti(L, -2, i++); - } - - return 1; -} - -/** Create a new workspace. - * \param A table with at least a name attribute. - * Optionnal attributes are: mwfact, ncol, nmaster and layout. - * \return A new workspace object. - */ -static int -luaA_workspace_new(lua_State *L) -{ - workspace_t *workspace; - int ncol, nmaster; - const char *name, *lay; - double mwfact; - layout_t *layout; - - luaA_checktable(L, 1); - - name = luaA_name_init(L); - mwfact = luaA_getopt_number(L, 1, "mwfact", 0.5); - ncol = luaA_getopt_number(L, 1, "ncol", 1); - nmaster = luaA_getopt_number(L, 1, "nmaster", 1); - lay = luaA_getopt_string(L, 1, "layout", "tile"); - - layout = name_func_lookup(lay, LayoutList); - - workspace = workspace_new(name, - layout, - mwfact, nmaster, ncol); - - return luaA_workspace_userdata_new(workspace); -} - -/** Set a workspace visible on a screen. - * \param A screen number. - */ -static int -luaA_workspace_screen_set(lua_State *L) -{ - workspace_t **workspace = luaA_checkudata(L, 1, "workspace"); - int screen = luaL_checknumber(L, 2) - 1; - luaA_checkscreen(screen); - workspace_view(*workspace, screen); - return 0; -} - -/** Get the screen the workspace is visible on. - * \return A screen number of nil if the workspace is not visible. - */ -static int -luaA_workspace_screen_get(lua_State *L) -{ - workspace_t **workspace = luaA_checkudata(L, 1, "workspace"); - int screen = workspace_screen_get(*workspace); - if(screen < 0) - return 0; - lua_pushnumber(L, screen + 1); - return 1; -} - -/** Give the focus to the latest focused client on a workspace. - */ -static int -luaA_workspace_focus_set(lua_State *L) -{ - workspace_t **workspace = luaA_checkudata(L, 1, "workspace"); - client_focus(focus_client_getcurrent(*workspace)); - return 0; -} - -/** Set the workspace master width factor. This value is used in various layouts to - * determine the size of the master window. - * \param The master width ratio value, between 0 and 1. - */ -static int -luaA_workspace_mwfact_set(lua_State *L) -{ - workspace_t **workspace = luaA_checkudata(L, 1, "workspace"); - double mwfact = luaL_checknumber(L, 2); - - if(mwfact < 1 && mwfact > 0) - { - (*workspace)->mwfact = mwfact; - (*workspace)->need_arrange = true; - } - else - luaL_error(L, "bad value, must be between 0 and 1"); - - return 0; -} - -/** Get the workspace master width factor. - * \return The master width ratio value. - */ -static int -luaA_workspace_mwfact_get(lua_State *L) -{ - workspace_t **workspace = luaA_checkudata(L, 1, "workspace"); - lua_pushnumber(L, (*workspace)->mwfact); - return 1; -} - -/** Set the number of columns. This is used in various layouts to set the number - * of columns used to display non-master windows. - * \param The number of columns, at least 1. - */ -static int -luaA_workspace_ncol_set(lua_State *L) -{ - workspace_t **workspace = luaA_checkudata(L, 1, "workspace"); - int ncol = luaL_checknumber(L, 2); - - if(ncol >= 1) - { - (*workspace)->ncol = ncol; - (*workspace)->need_arrange = true; - } - else - luaL_error(L, "bad value, must be greater than 1"); - - return 0; -} - -/** Get the number of columns used to display non-master windows on this workspace. - * \return The number of column. - */ -static int -luaA_workspace_ncol_get(lua_State *L) -{ - workspace_t **workspace = luaA_checkudata(L, 1, "workspace"); - lua_pushnumber(L, (*workspace)->ncol); - return 1; -} - -/** Set the number of master windows. This is used in various layouts to - * determine how many windows are in the master area. - * \param The number of master windows. - */ -static int -luaA_workspace_nmaster_set(lua_State *L) -{ - workspace_t **workspace = luaA_checkudata(L, 1, "workspace"); - int nmaster = luaL_checknumber(L, 2); - - if(nmaster >= 0) - { - (*workspace)->nmaster = nmaster; - (*workspace)->need_arrange = true; - } - else - luaL_error(L, "bad value, must be greater than 0"); - - return 0; -} - -/** Get the number of master windows of the workspace. - * \return The number of master windows. - */ -static int -luaA_workspace_nmaster_get(lua_State *L) -{ - workspace_t **workspace = luaA_checkudata(L, 1, "workspace"); - lua_pushnumber(L, (*workspace)->nmaster); - return 1; -} - -/** Get the workspace name. - * \return The workspace name. - */ -static int -luaA_workspace_name_get(lua_State *L) -{ - workspace_t **workspace = luaA_checkudata(L, 1, "workspace"); - lua_pushstring(L, (*workspace)->name); - return 1; -} - -/** Set the workspace name. - * \param A string with the new workspace name. - */ -static int -luaA_workspace_name_set(lua_State *L) -{ - workspace_t **workspace = luaA_checkudata(L, 1, "workspace"); - const char *name = luaL_checkstring(L, 2); - p_delete(&(*workspace)->name); - (*workspace)->name = a_strdup(name); - return 0; -} - -/** Handle workspace garbage collection. - */ -static int -luaA_workspace_gc(lua_State *L) -{ - workspace_t **workspace = luaA_checkudata(L, 1, "workspace"); - workspace_unref(workspace); - *workspace = NULL; - return 0; -} - -/** Get the visible workspace for a screen. - * \param A screen number. - */ -static int -luaA_workspace_visible_get(lua_State *L) -{ - int screen = luaL_checknumber(L, 1) - 1; - luaA_checkscreen(screen); - - if(globalconf.screens[screen].workspace) - return luaA_workspace_userdata_new(globalconf.screens[screen].workspace); - return 0; -} - -/** Get the layout of the workspace. - * \return The layout name. - */ -static int -luaA_workspace_layout_get(lua_State *L) -{ - workspace_t **workspace = luaA_checkudata(L, 1, "workspace"); - const char *name = a_strdup(name_func_rlookup((*workspace)->layout, LayoutList)); - lua_pushstring(L, name); - return 1; -} - -/** Set the layout of the workspace. - * \param A layout name. - */ -static int -luaA_workspace_layout_set(lua_State *L) -{ - workspace_t **workspace = luaA_checkudata(L, 1, "workspace"); - const char *name = luaL_checkstring(L, 2); - layout_t *l = name_func_lookup(name, LayoutList); - - if(l) - { - (*workspace)->layout = l; - (*workspace)->need_arrange = true; - } - else - luaL_error(L, "unknown layout: %s", name); - - return 0; -} - -/** Create a new userdata from a workspace. - * \param t The workspace. - * \return The luaA_settype return value. - */ -int -luaA_workspace_userdata_new(workspace_t *w) -{ - workspace_t **ws = lua_newuserdata(globalconf.L, sizeof(workspace_t *)); - *ws = w; - workspace_ref(ws); - return luaA_settype(globalconf.L, "workspace"); -} - -const struct luaL_reg awesome_workspace_methods[] = -{ - { "new", luaA_workspace_new }, - { "get", luaA_workspace_get}, - { "visible_get", luaA_workspace_visible_get }, - { NULL, NULL } -}; -const struct luaL_reg awesome_workspace_meta[] = -{ - { "add", luaA_workspace_add }, - { "screen_set", luaA_workspace_screen_set }, - { "screen_get", luaA_workspace_screen_get }, - { "focus_set", luaA_workspace_focus_set }, - { "mwfact_set", luaA_workspace_mwfact_set }, - { "mwfact_get", luaA_workspace_mwfact_get }, - { "ncol_set", luaA_workspace_ncol_set }, - { "ncol_get", luaA_workspace_ncol_get }, - { "nmaster_set", luaA_workspace_nmaster_set }, - { "nmaster_get", luaA_workspace_nmaster_get }, - { "name_get", luaA_workspace_name_get }, - { "name_set", luaA_workspace_name_set }, - { "layout_get", luaA_workspace_layout_get }, - { "layout_set", luaA_workspace_layout_set }, - { "__eq", luaA_workspace_eq }, - { "__gc", luaA_workspace_gc }, - { "__tostring", luaA_workspace_tostring }, - { NULL, NULL }, -}; -// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80