142 Commits

Author SHA1 Message Date
OldMan
6d1bd844f7 Tag: add uicb functions: tag_next_visible & tag_prev_visible. 2010-04-23 16:36:11 +06:00
OldMan
1d9bb77d83 Tag: When adding a new tag, it is selected. Otherwise, if autohide is enabled, the new tag is not visible. 2010-04-23 13:36:34 +06:00
OldMan
d24e5e911f Tag: Fix: if delete last tag, then none tag selected. 2010-04-23 12:56:02 +06:00
Martin Duquesnoy
07db3fafbd Menu: Fix item height 2010-04-22 17:56:35 +02:00
Martin Duquesnoy
d38e7598a4 Client: uicb_client_select warp pointer on the client to avoid Bug #51 signaled by bacardi55 2010-04-22 17:40:55 +02:00
Martin Duquesnoy
add85a7509 Infobar: Fix toggle_autohide with whole infobar replacement 2010-04-20 18:27:49 +02:00
Martin Duquesnoy
f9157a4dda Merge branch 'oldman' of github.com:xorg62/wmfs 2010-04-20 18:11:09 +02:00
Martin Duquesnoy
f8115d686d Tag/Clients: Add client_ignore tag option (~Feature #6 requested by Elpinoutoufou) 2010-04-20 18:10:42 +02:00
OldMan
236b86ff0a Infobar: Add toggle_tagautohide uicb function. 2010-04-20 20:11:59 +06:00
Philippe Pepiot
46608a14be Fix possible use of unitialized variables 2010-04-20 14:25:57 +02:00
Philippe Pepiot
0e8ffff152 Kill status script in quit() 2010-04-20 03:43:28 +02:00
Philippe Pepiot
52dba6418e fix posible issue with statusbar when reloading wmfs
spawn() now return the child pid
2010-04-20 03:32:22 +02:00
Philippe Pepiot
e6b26eafc2 Merge branch 'master' of git.philpep.org:wmfs into philpep 2010-04-20 00:37:47 +02:00
Philippe Pepiot
a635e7c2d6 Parse: fix possible issue in fetch_section_first() 2010-04-20 00:13:39 +02:00
Philippe Pepiot
5271222e38 Merge branch 'master' of git.philpep.org:wmfs into philpep 2010-04-19 23:06:18 +02:00
Martin Duquesnoy
7119d3cc25 Tag: Improve and fix some bugs in tag_delete 2010-04-19 22:32:41 +02:00
Philippe Pepiot
c81312feff Merge branch 'master' of git.philpep.org:wmfs into philpep 2010-04-19 18:24:25 +02:00
Martin Duquesnoy
fe22703fea Merge branch 'oldman' of github.com:xorg62/wmfs 2010-04-19 16:16:55 +02:00
Philippe Pepiot
2da44ff4d8 Merge branch 'master' of git.philpep.org:wmfs into philpep 2010-04-19 13:59:23 +02:00
Martin Duquesnoy
892b705f95 Tag: Fix 2nd segfault -> tag_new 2010-04-19 01:34:23 +02:00
Martin Duquesnoy
feadae05c8 Tag: Fix segfault in tag_del (Bug #50 signaled by addikt1ve) 2010-04-19 01:29:09 +02:00
Philippe Pepiot
ba841c74b3 Merge branch 'master' of git.philpep.org:wmfs into philpep 2010-04-18 23:38:08 +02:00
Martin Duquesnoy
129a21bada Tag: add tag_new and tag_del function *Dynamic taggin* 2010-04-18 22:25:26 +02:00
Philippe Pepiot
dd3d490c39 Merge branch 'master' of git.philpep.org:wmfs into philpep 2010-04-18 20:24:49 +02:00
Martin Duquesnoy
f8a3cc0e0e Merge branch 'philpep' of git.wmfs.info:wmfs 2010-04-18 19:44:41 +02:00
Martin Duquesnoy
de672fc7ad Tag: Fix tag swapping when there clients in both 2010-04-18 19:20:09 +02:00
Philippe Pepiot
06d014722f Merge branch 'master' of git.philpep.org:wmfs into philpep 2010-04-18 19:12:27 +02:00
Martin Duquesnoy
5ccc31f7ec Tag: Fix tag_swap() with clients 2010-04-18 19:02:13 +02:00
Philippe Pepiot
37d6d105d8 Merge branch 'master' of git.philpep.org:wmfs into philpep 2010-04-18 19:00:23 +02:00
Martin Duquesnoy
3e2d4a6a01 Tag: Fix test in tag_swap() 2010-04-18 18:58:57 +02:00
Philippe Pepiot
eb16ebfb7f Merge branch 'master' of git.philpep.org:wmfs into philpep 2010-04-18 18:53:19 +02:00
Philippe Pepiot
d0d62c798b Build System: permit user to change CFLAGS 2010-04-18 18:51:54 +02:00
Martin Duquesnoy
0f25f75f0d Tag: Add tag_swap and uicb function: tag_swap with cmd = <tag>, tag_swap_next & tag_swap_prev 2010-04-18 18:50:08 +02:00
Martin Duquesnoy
8c0e37cb38 Infobar: Add autohide option in [tags]: Hide empty tags in tag list (Feature #24 requested by Erus) 2010-04-18 17:38:12 +02:00
Martin Duquesnoy
3811d61858 Parser: Fix fetch_section_first when the section doesn't exist 2010-04-17 14:24:08 +02:00
OldMan
84f6aa31d0 Add bar future to draw graph with 'wmfs -s \g[x;y;w;h;#color;data]\' 2010-04-17 15:31:04 +06:00
Martin Duquesnoy
5875af2949 Selbar: Put ... only when sel->title lenght > max_lenght 2010-04-16 19:41:02 +02:00
Martin Duquesnoy
49b9a08fab Selbar/Conf: Add max_lenght option to cut title lenght (requested by Erus) 2010-04-16 19:31:33 +02:00
Philippe Pepiot
c7824780fa Fix wait for sleep() when exit 2010-04-15 20:37:34 +02:00
Philippe Pepiot
b472a08490 If conf.status_timing is 0 launch one time 2010-04-15 19:31:04 +02:00
Martin Duquesnoy
55e74cd849 Selbar: Unmap selbar if there is no selected client 2010-04-15 17:59:32 +02:00
Martin Duquesnoy
8e3e10f041 Client: Improve clientlist 2010-04-15 13:49:31 +02:00
Martin Duquesnoy
d5e1f1da78 Conf: Set bar color as default selbar color 2010-04-15 13:19:41 +02:00
Philippe Pepiot
aca9e78491 Parse: better converting function in string_to_opt 2010-04-15 02:22:44 +02:00
Philippe Pepiot
18b702c112 Parse: return sections in real order 2010-04-15 01:57:35 +02:00
Philippe Pepiot
7f7bbd1f09 Parse: add comment and make some code cosmetics 2010-04-15 01:30:23 +02:00
Philippe Pepiot
d6c2902d77 config.c: mouse section size is useless here 2010-04-15 01:13:40 +02:00
Philippe Pepiot
c8bb465bb0 Fix possible segfault when no [selbar] in config 2010-04-15 01:09:22 +02:00
Philippe Pepiot
891760bfac Missing param when merging 2010-04-14 21:17:54 +02:00
Philippe Pepiot
657dc33d63 Merge branch 'oldman' of git://github.com/xorg62/wmfs
Conflicts:
	src/config.c
2010-04-14 21:15:56 +02:00
OldMan
5363a7a8a9 Menu as Clientlist 2010-04-14 19:59:53 +06:00
Philippe Pepiot
3274e3f4ad config: fix wrong keybind order 2010-04-14 14:42:18 +02:00
Martin Duquesnoy
fb905b55c5 Tag: Fix tag_transfert bug if tag > conf.ntag[screen] 2010-04-14 01:45:33 +02:00
Philippe Pepiot
41bf8e2052 [parse] add free_conf() 2010-04-14 01:18:45 +02:00
Philippe Pepiot
5c5e137fdd [parse] print warning when option is unused 2010-04-14 00:49:09 +02:00
Philippe Pepiot
9f7f4c40e4 Fix segfault when fetch_opt on a NULL section 2010-04-13 22:48:50 +02:00
Philippe Pepiot
8975e04777 Fix layout menu in reverse order 2010-04-13 22:39:21 +02:00
Philippe Pepiot
d37dc481a1 New fonctions in parser
fetch_(opt|section)_first -> return the first (section|opt) found
fetch_(opt|section)_count -> return the size of (section|opt)
2010-04-13 22:05:01 +02:00
Philippe Pepiot
77d95275f0 Merge branch 'master' of git.philpep.org:wmfs into philpep 2010-04-13 21:03:06 +02:00
Martin Duquesnoy
81e6a63c1f Conf: Fix multi mouse section of multi button section 2010-04-13 21:01:25 +02:00
Philippe Pepiot
0d9f8d887d Merge branch 'master' of git.philpep.org:wmfs into philpep 2010-04-13 20:51:01 +02:00
Martin Duquesnoy
9a38a64ced Conf: Fix multi mouse section of titlebar 2010-04-13 20:49:42 +02:00
Martin Duquesnoy
b4705bbaa7 Conf: Fix button section bug 2010-04-13 20:41:41 +02:00
Martin Duquesnoy
005f06c15e Merge branch 'philpep' of git.wmfs.info:wmfs 2010-04-13 20:08:25 +02:00
Philippe Pepiot
761afe51a0 Merge branch 'master' of git.philpep.org:wmfs into philpep 2010-04-13 19:58:58 +02:00
Philippe Pepiot
9b33623d33 New parser in use.
Warning : be prudent :)
2010-04-13 19:57:02 +02:00
OldMan
6f2d6385ac Merge branch 'oldman' into sb-sec 2010-04-13 18:31:21 +06:00
OldMan
a713e34b87 Merge branch 'master' into sb-sec 2010-04-13 18:31:14 +06:00
OldMan
db90cf65c9 Merge branch 'sb-sec' into oldman 2010-04-13 10:21:24 +06:00
OldMan
1ddc714196 Conf: section 'selbar' in section 'bar' 2010-04-13 10:15:40 +06:00
Philippe Pepiot
611a5fc38d New parser (not yet in use) 2010-04-13 01:43:12 +02:00
Martin Duquesnoy
b0b74b46eb Code cosmetic.. 2010-04-12 18:33:32 +02:00
Philippe Pepiot
b31d54b7e6 Abusive use of _strdup in confparse/util.c
String was also strdup into erase_(delim|sec)_content
2010-04-11 23:37:17 +02:00
Martin Duquesnoy
7908d3075c Merge branch 'philpep' of git.wmfs.info:wmfs 2010-04-11 20:19:00 +02:00
Philippe Pepiot
cf652aab50 Fix memleak in confparse.c 2010-04-11 17:54:33 +02:00
Philippe Pepiot
914b9f11c9 Fix abusive use of _strdup() in get_nsec 2010-04-11 17:36:45 +02:00
OldMan
dcb48cc2c5 Merge branch 'misc' into oldman 2010-04-11 16:59:00 +06:00
OldMan
9c693212bb Misc: client_round option 2010-04-11 16:57:07 +06:00
OldMan
d525e3ace1 Misc: focus_pointer_click option 2010-04-11 16:15:29 +06:00
OldMan
0bed70e52c InfoBar: taglist optimization 2010-04-11 12:47:58 +06:00
Martin Duquesnoy
61858bbe64 Config: Fix possible segfault with layout system switch 2010-04-10 23:41:27 +02:00
Philippe Pepiot
f6486d803c Fix possible segfault when parsing options 2010-04-10 18:38:21 +02:00
OldMan
8b16176edc Menu.submenu: fix segfault bug (thanks Martin for debug). 2010-04-10 19:54:03 +06:00
OldMan
4138894db1 Menuitem option 'submenu'. Draw bullet '>' on the right. 2010-04-10 18:53:30 +06:00
Martin Duquesnoy
8a45d219bd Update README 2010-04-10 13:55:26 +02:00
Martin Duquesnoy
b4c326ebaf Menu: Fix screen limits (bug with multi-head) 2010-04-10 13:48:12 +02:00
OldMan
c5c307deea Menuitem option 'check'. Draw bullet '*' on the left (ugly, but simple). 2010-04-10 17:16:24 +06:00
OldMan
590acffb62 Bugfix: Menu get out of the screen view area. Feature: New menu option 'align'. 2010-04-10 16:46:32 +06:00
OldMan
a0258c13d0 Menu: Little optimization 2010-04-10 11:33:21 +06:00
Martin Duquesnoy
466ebca9ea EWMH: Fix focus on _NET_WM_STATE_FULLSCREEN (Bug #42 signaled by tamtam) 2010-04-08 13:20:51 +02:00
Martin Duquesnoy
fbb36877dc EWMH: Improve _NET_WM_STATE_FULLSCREEN management 2010-04-08 12:33:52 +02:00
Martin Duquesnoy
ffaa243644 Conf: Improve default wmfsrc and set new version 2010-04-07 01:34:03 +02:00
Martin Duquesnoy
87a41561e7 Tag: Fix layout update in case of additional tag in tag_set 2010-04-07 00:57:39 +02:00
Martin Duquesnoy
5c439c245c Tag: Add multitag support (Feature #38 requested by Chacha^Wmarkand): button 3 click on tag to add it. (tagtransfert is now button 2 by default) 2010-04-07 00:33:00 +02:00
Martin Duquesnoy
e920b99951 Launcher: Add Control-p/n to manage historic (vim-like) requested by Bram 2010-04-06 21:15:56 +02:00
Martin Duquesnoy
22b405cba8 Launcher: Add historic for launcher (Feature #8 requested by bacardi55) 2010-04-06 21:06:21 +02:00
Martin Duquesnoy
6f82c73409 Tag: Add uicb_tag_urgent to go to urgent tag (Feature #37 request bien Erus) 2010-04-06 01:33:18 +02:00
Martin Duquesnoy
b38db34de5 Client: Fix possible bug in removing focus when client wanted tag is set 2010-04-05 16:41:28 +02:00
Martin Duquesnoy
8c24370a9f Conf: Reverse allowing border height of client to 0 2010-04-05 15:10:08 +02:00
Martin Duquesnoy
fb8daed2b5 Layout: Fix free geometry of client 2010-04-04 20:04:54 +02:00
Martin Duquesnoy
ee13255297 Client/Event/Tag: Fix XUrgencyHint support 2010-04-04 15:42:51 +02:00
Martin Duquesnoy
9c154fd0f3 Client/Event/Tag: Add XUrgencyHint support (colorize tag where there is an urgent client) 2010-04-04 15:13:02 +02:00
Martin Duquesnoy
b5dd942fd1 Conf: Allow border height of client to 0 (Feature #34 requested by addikt1ve) 2010-04-03 23:10:25 +02:00
Martin Duquesnoy
321669eb3a Draw: Fix possible segfault in textw (securize strcpy) 2010-03-28 16:09:00 +02:00
Martin Duquesnoy
aa9609b5cf Draw: Replace statustext_image by parse_color_block, remove image stuff in status.c (draw_text image stuff is sufficient) and update version 2010-03-28 15:41:54 +02:00
Martin Duquesnoy
09418c6dd7 Draw: Can put image everywhere we can habitually put text with same sequences than in statustext: \i[x;y;w;h;/image/path.ext]\ (example: layout, tag: http://omploader.org/vM3lzNg) 2010-03-28 14:49:10 +02:00
Martin Duquesnoy
0ce0d1a352 Draw: Add Imlib2 support to draw image (optional feature, work only if have imlib2): statustext block to draw image: \i[x;y;width;height;imagepath.extension]\ 2010-03-28 03:36:56 +02:00
OldMan
c350bb45d0 Conf: Buttons as indicators of client mode (Feature #33) 2010-03-25 19:53:00 +01:00
Martin Duquesnoy
06a9c44792 Client: Add ignore_next_client_rules uicb function requested by Armael. 2010-03-25 19:40:21 +01:00
Martin Duquesnoy
c5da009b7a Conf: Add [misc] status_path option to choose status script path 2010-03-25 19:19:24 +01:00
Martin Duquesnoy
23b0539686 Client: Reverse client_configure last modif 2010-03-25 13:46:59 +01:00
Martin Duquesnoy
8a236cc7ac Client: Update selbar if selected client get a new title 2010-03-25 12:36:34 +01:00
Martin Duquesnoy
4199b7bb50 Event: manage expose event for selbar 2010-03-24 19:15:11 +01:00
Martin Duquesnoy
842bc7d3ce Infobar: Add selbar; title of selected client in infobar (Feature #31 requested by markand), conf: [bar] selbar = true/false 2010-03-24 18:03:17 +01:00
Martin Duquesnoy
fab6a9f584 Tag: Fix mad behavior when wanting to transfer a client on the its tag 2010-03-04 21:54:18 +01:00
Martin Duquesnoy
7a714c03a9 Screen: Add screen_prev_sel function to go to the last used screen. (Feature #30 requested by Erus) 2010-02-26 23:40:16 +01:00
Martin Duquesnoy
2e0b050be3 Update version 2010-02-26 21:07:57 +01:00
OldMan
ade723b6bc Tag: Add functions to transfert selected client to next/previous tag. 2010-02-25 20:56:49 +01:00
OldMan
2b7d1c115d Client: Keep free-size after toggle_{free, max}. 2010-02-25 20:48:24 +01:00
Martin Duquesnoy
7e44e4b314 Tag: Add tag_prev_sel function request by Erus (Feature #29) 2010-02-25 20:39:04 +01:00
Martin Duquesnoy
77cb589f03 Mouse: Fix move_tag_client. 2010-02-07 17:56:48 +01:00
Martin Duquesnoy
56079ebdfe Infobar: Add option to move layout button before of after tags list (Feature #20 requested by Erus.) 2010-02-07 17:27:42 +01:00
Martin Duquesnoy
881ac9f68f Status: Add status.c, clean statutext fonction and add located text stuff: \s[x;y;#color;text]\. 2010-02-04 02:58:28 +01:00
Martin Duquesnoy
55fa590785 Revert "Conf: Fix bug (last keybind)"
This reverts commit a164eb8f7c.
2010-02-03 16:09:12 +01:00
Martin Duquesnoy
a164eb8f7c Conf: Fix bug (last keybind) 2010-02-03 15:42:59 +01:00
Martin Duquesnoy
888b2a7467 Infobar: Set buffers size to MAXSS 2010-01-31 16:27:27 +01:00
Philippe Pepiot
6f1624f43b Init: Define layout_list statically 2010-01-24 19:41:24 +01:00
Philippe Pepiot
04bef9a4b8 rc/status.sh: be posix compliant 2010-01-24 16:44:26 +01:00
Philippe Pepiot
344d80206c init: fix possible segfault if HOME not set 2010-01-20 11:38:32 +01:00
Philippe Pepiot
c6b97b7892 init: end layout list with { NULL, NULL } 2010-01-20 11:29:59 +01:00
Martin Duquesnoy
6c0a0b62b6 Infobar: Remove debug stuff ... again... 2010-01-10 16:33:56 +01:00
Martin Duquesnoy
bc94d42372 Infobar: Remove useless strncpy. 2010-01-10 16:32:49 +01:00
Martin Duquesnoy
f4d683f17f Infobar: Remove debug stuff 2010-01-10 15:07:19 +01:00
Martin Duquesnoy
d8afcfa013 Infobar: Fix strncpy mistake. 2010-01-10 15:06:37 +01:00
Martin Duquesnoy
af0d459b4c Infobar: Improve and simplify infobar_draw_statustext. 2010-01-10 03:00:48 +01:00
Martin Duquesnoy
b766375db8 Infobar: Code cosmetic. 2010-01-07 18:33:16 +01:00
Martin Duquesnoy
26498dc07b Infobar: Add bar feature in infobar_draw_statustext to make rectangle with wmfs -s -> \b[xx;yy;width;height;#color]\ *TEST* 2010-01-07 18:27:34 +01:00
Martin Duquesnoy
000a1f4c3d Infobar: Add bar feature in infobar_draw_statustext to make rectangle with wmfs -s -> \b[xx;yy;width;height;#color]\ *TEST* 2010-01-03 23:02:25 +01:00
Martin Duquesnoy
f0daf5ba20 Init: Replace system by spawn at the first execution of status_path 2010-01-02 20:31:42 +01:00
Martin Duquesnoy
250518c2a4 Wmfsrc: Add status_timing in default conf 2010-01-02 18:31:19 +01:00
Martin Duquesnoy
7acf0139d4 Infobar/Wmfs: Fix infobar_draw_statustext, remove useless screen_count() 2010-01-02 17:38:13 +01:00
Martin Duquesnoy
e4bbe15fc4 Infobar: Fix memleak in infobar_draw_statustext by replacing pointer to array 2010-01-02 16:50:37 +01:00
31 changed files with 2941 additions and 1191 deletions

View File

@@ -24,8 +24,7 @@ project(${PROJECT_NAME} C)
# Definition of the wmfs source
set(wmfs_src
src/confparse/util.c
src/confparse/confparse.c
src/parse/parse.c
src/barwin.c
src/client.c
src/config.c
@@ -42,6 +41,7 @@ set(wmfs_src
src/menu.c
src/mouse.c
src/screen.c
src/status.c
src/tag.c
src/util.c
src/viwmfs.c
@@ -51,11 +51,10 @@ set(wmfs_src
add_executable(wmfs ${wmfs_src})
# Set the version
set(VERSION "WMFS-201001")
set(VERSION "WMFS-201004")
# FLAGS
set(CFLAGS "-g -Wall -ansi")
set(CMAKE_C_FLAGS ${CFLAGS})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -ansi")
# Linker FLAGS
@@ -105,6 +104,8 @@ pkg_check_modules(WMFS_REQUIRED REQUIRED
freetype2
xft)
# Optional dependencies check
# Check for xinerama
pkg_check_modules(HAVE_XINERAMA xinerama)
if(HAVE_XINERAMA_FOUND)
@@ -123,11 +124,20 @@ else()
set(WMFS_HAVE_XRANDR "")
endif()
# Check for Imlib
pkg_check_modules(HAVE_IMLIB imlib2)
if(HAVE_IMLIB_FOUND)
set(WMFS_HAVE_IMLIB "#define HAVE_IMLIB")
set(LIBRARIES_TO_LINK ${LIBRARIES_TO_LINK} Imlib2)
else()
set(WMFS_HAVE_IMLIB "")
endif()
target_link_libraries(wmfs ${LIBRARIES_TO_LINK})
# Messages
message("Project version: ${VERSION}")
message("Using these CFLAGS: ${CFLAGS}")
message("Using these CFLAGS: ${CMAKE_C_FLAGS}")
message("Using these LDFLAGS: ${LDFLAGS}")
message("Linking with theses libraries : ${LIBRARIES_TO_LINK}")
@@ -216,7 +226,7 @@ endif()
set(WMFS_VERSION ${VERSION})
set(WMFS_COMPILE_MACHINE ${CMAKE_SYSTEM_PROCESSOR})
set(WMFS_COMPILE_BY $ENV{USER})
set(WMFS_COMPILE_FLAGS ${CFLAGS})
set(WMFS_COMPILE_FLAGS ${CMAKE_C_FLAGS})
set(WMFS_LINKED_LIBS ${LIBRARIES_TO_LINK})
set(WMFS_SYSCONFDIR ${XDG_CONFIG_DIR}/${PROJECT_NAME})
set(WMFS_SOURCE_DIR ${SOURCE_DIR})

3
README
View File

@@ -13,6 +13,7 @@ REQUIREMENT :
- freetype2
- libxinerama (optional)
- libxrandr (optional)
- imlib2 (optional)
- libxft
- libx11
- CMake >= 2.6
@@ -33,4 +34,4 @@ If you have doxygen installed you can generate doxygen documentation via custom
DISTROS :
- wmfs port for FreeBSD at x11-wm/wmfs
- wmfs is available with AUR in ArchLinux
- wmfs is available with AUR in ArchLinux (wmfs or wmfs-git)

View File

@@ -5,9 +5,7 @@
statustext()
{
local DATE=`date`
wmfs -s "$DATE"
wmfs -s "`date`"
}
statustext

View File

@@ -67,6 +67,7 @@ barwin_create(Window parent,
|ButtonMask|MouseMask
|ExposureMask|VisibilityChangeMask
|StructureNotifyMask|SubstructureRedirectMask;
if(entermask)
at.event_mask |= EnterWindowMask|LeaveWindowMask|FocusChangeMask;
@@ -107,6 +108,9 @@ barwin_create(Window parent,
void
barwin_draw_text(BarWindow *bw, int x, int y, char *text)
{
if(!text)
return;
/* Background color of the text if there is stipple */
if(bw->stipple)
draw_rectangle(bw->dr, x - 4, 0, textw(text) + 8, bw->geo.height, bw->bg);
@@ -214,12 +218,10 @@ barwin_unmap_subwin(BarWindow *bw)
void
barwin_move(BarWindow *bw, int x, int y)
{
CHECK(bw);
if(!bw || (bw->geo.x == x && bw->geo.y == y))
return;
bw->geo.x = x;
bw->geo.y = y;
XMoveWindow(dpy, bw->win, x, y);
XMoveWindow(dpy, bw->win, (bw->geo.x = x), (bw->geo.y = y));
return;
}
@@ -232,7 +234,8 @@ barwin_move(BarWindow *bw, int x, int y)
void
barwin_resize(BarWindow *bw, uint w, uint h)
{
CHECK(bw);
if(!bw || (bw->geo.width == w && bw->geo.height == h))
return;
bw->geo.width = w;
bw->geo.height = h;

View File

@@ -40,6 +40,7 @@ client_attach(Client *c)
{
if(clients)
clients->prev = c;
c->next = clients;
clients = c;
@@ -96,7 +97,8 @@ client_get_next(void)
return NULL;
for(c = sel->next; c && ishide(c, selscreen); c = c->next);
if(!c)
if(!c && conf.client_round)
for(c = clients; c && ishide(c, selscreen); c = c->next);
return c;
@@ -117,7 +119,7 @@ client_get_prev(void)
if(!ishide(d, selscreen))
c = d;
if(!c)
if(!c && conf.client_round)
for(; d; d = d->next)
if(!ishide(d, selscreen))
c = d;
@@ -242,7 +244,7 @@ client_focus(Client *c)
sel->flags &= ~AboveFlag;
frame_update(sel);
mouse_grabbuttons(sel, False);
mouse_grabbuttons(sel, !conf.focus_pclick);
}
if((sel = c))
@@ -265,19 +267,32 @@ client_focus(Client *c)
client_raise(c);
}
if(tags[sel->screen][sel->tag].abovefc
&& !conf.focus_fmouse)
if(tags[sel->screen][sel->tag].abovefc && !conf.focus_fmouse)
client_above(sel);
if(c->flags & UrgentFlag)
{
c->flags &= ~UrgentFlag;
tags[c->screen][c->tag].urgent = False;
infobar_draw_taglist(c->screen);
}
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
if(conf.bars.selbar)
infobar_draw_selbar(sel->screen);
}
else
{
XSetInputFocus(dpy, ROOT, RevertToPointerRoot, CurrentTime);
if(conf.bars.selbar)
infobar_draw_selbar(selscreen);
}
return;
}
/* The following function have the same point :
/* The following functions have the same point :
* find a client member with a Window {{{
*/
@@ -373,6 +388,8 @@ client_get_name(Client *c)
int rf;
ulong ir, il;
IFREE(c->title);
/* This one instead XFetchName for utf8 name support */
if(XGetWindowProperty(dpy, c->win, net_atom[net_wm_name], 0, 4096,
False, net_atom[utf8_string], &rt, &rf, &ir, &il, (uchar**)&c->title) != Success)
@@ -383,12 +400,16 @@ client_get_name(Client *c)
if(!c->title)
{
XFetchName(dpy, c->win, &(c->title));
if(!c->title)
c->title = _strdup("WMFS");
}
frame_update(c);
if(conf.bars.selbar && c == sel)
infobar_draw_selbar(c->screen);
return;
}
@@ -414,7 +435,8 @@ client_hide(Client *c)
Bool
ishide(Client *c, int screen)
{
if(c->tag == seltag[screen] && c->screen == screen)
if(((c->tag == seltag[screen] || c->tag == MAXTAG + 1) && c->screen == screen)
|| tags[screen][seltag[screen]].tagad & TagFlag(c->tag))
return False;
return True;
@@ -555,6 +577,7 @@ client_manage(Window w, XWindowAttributes *wa, Bool ar)
c->ogeo.y = c->geo.y = my;
c->ogeo.width = c->geo.width = wa->width;
c->ogeo.height = c->geo.height = wa->height;
c->free_geo = c->geo;
c->tag = seltag[c->screen];
c->layer = (sel && sel->layer > 0) ? sel->layer : 1;
@@ -565,13 +588,21 @@ client_manage(Window w, XWindowAttributes *wa, Bool ar)
frame_create(c);
client_size_hints(c);
XChangeWindowAttributes(dpy, c->win, CWEventMask, &at);
XSetWindowBorderWidth(dpy, c->win, 0); /* client win sould _not_ have borders */
/* client win should _not_ have borders */
XSetWindowBorderWidth(dpy, c->win, 0);
mouse_grabbuttons(c, False);
/* Transient */
if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success))
for(t = clients; t && t->win != trans; t = t->next);
if(t)
{
c->tag = t->tag;
c->screen = t->screen;
}
if(!(c->flags & FreeFlag)
&& (rettrans == Success || (c->flags & HintFlag)))
c->flags |= FreeFlag;
@@ -669,7 +700,11 @@ client_moveresize(Client *c, XRectangle geo, Bool r)
c->flags &= ~MaxFlag;
c->geo = c->ogeo = geo;
if((c->screen = screen_get_with_geo(c->geo.x, c->geo.y)) != os)
if(c->flags & FreeFlag || tags[c->screen][c->tag].layout.func == freelayout)
c->free_geo = geo;
if((c->screen = screen_get_with_geo(c->geo.x, c->geo.y)) != os
&& c->tag != MAXTAG + 1)
c->tag = seltag[c->screen];
frame_moveresize(c, c->geo);
@@ -826,6 +861,12 @@ client_set_wanted_tag(Client *c)
XClassHint xch = { 0 };
int i, j, k;
if(conf.ignore_next_client_rules)
{
conf.ignore_next_client_rules = False;
return;
}
XGetClassHint(dpy, c->win, &xch);
for(i = 0; i < screen_count(); ++i)
@@ -839,7 +880,10 @@ client_set_wanted_tag(Client *c)
c->tag = j;
if(c->tag != seltag[selscreen])
{
tags[c->screen][c->tag].request_update = True;
client_focus(NULL);
}
tags[c->screen][c->tag].layout.func(c->screen);
}
@@ -862,7 +906,7 @@ client_update_attributes(Client *c)
XChangeProperty(dpy, c->win, ATOM("_WMFS_SCREEN"), XA_CARDINAL, 32,
PropModeReplace, (uchar*)&(c->screen), 1);
f = (c->flags & FreeFlag) ? True : False;
f = (c->flags & FreeFlag);
XChangeProperty(dpy, c->win, ATOM("_WMFS_ISFREE"), XA_CARDINAL, 32,
PropModeReplace, (uchar*)&f, 1);
@@ -890,6 +934,8 @@ client_raise(Client *c)
void
uicb_client_raise(uicb_t cmd)
{
CHECK(sel);
client_raise(sel);
return;
@@ -1119,3 +1165,121 @@ uicb_client_resize(uicb_t cmd)
return;
}
/** Ignore next client rules
*\param cmd uicb_t type
*/
void
uicb_ignore_next_client_rules(uicb_t cmd)
{
conf.ignore_next_client_rules = !conf.ignore_next_client_rules;
return;
}
/** Show clientlist menu
*\param cmd uicb_t type
*/
void
uicb_clientlist(uicb_t cmd)
{
int i, d, u, x, y;
int n = 0;
Window w;
Client *c = NULL;
screen_get_sel();
for(c = clients; c; c = c->next)
if(!ishide(c, selscreen))
++n;
if(n > 0)
{
if(clientlist.nitem)
menu_clear(&clientlist);
menu_init(&clientlist, "clientlist", n,
/* Colors */
conf.colors.tagselbg,
conf.colors.tagselfg,
conf.colors.bar,
conf.colors.text);
for(i = 0, c = clients; c; c = c->next)
if(!ishide(c, selscreen))
{
sprintf(clist_index[i].key, "%d", i);
clist_index[i].client = c;
menu_new_item(&clientlist.item[i], c->title,
uicb_client_select, clist_index[i].key);
if(c == sel)
clientlist.item[i].check = name_to_func("check_clist", func_list);
i++;
}
clist_index[i].client = NULL;
XQueryPointer(dpy, ROOT, &w, &w, &x, &y, &d, &d, (uint *)&u);
menu_draw(clientlist, x, y);
}
return;
}
/** Select client
*\param cmd uicb_t type clientlist index
*/
void
uicb_client_select(uicb_t cmd)
{
int i;
Window w;
int d, x, y;
for(i = 0; i < MAXCLIST && clist_index[i].client; ++i)
if(!strcmp(cmd, clist_index[i].key))
{
client_focus(clist_index[i].client);
client_raise(clist_index[i].client);
/* Move pointer on client */
XQueryPointer(dpy, ROOT, &w, &w, &x, &y, &d, &d, (uint *)&d);
XWarpPointer(dpy, ROOT, ROOT, x, y, d, d,
clist_index[i].client->geo.x + clist_index[i].client->geo.width / 2,
clist_index[i].client->geo.y + clist_index[i].client->geo.height / 2);
}
return;
}
/** Check clientlist menu fake function
* \param cmd uicb_t type unused
*/
Bool
uicb_checkclist(uicb_t cmd)
{
return True;
}
/** Set selected client on all tag (ignore tags
*\para cmd uicb_t type unused
*/
void
uicb_client_ignore_tag(uicb_t cmd)
{
CHECK(sel);
screen_get_sel();
sel->tag = ((sel->tag == MAXTAG + 1) ? seltag[selscreen] : MAXTAG + 1);
arrange(sel->screen, True);
return;
}

View File

@@ -32,49 +32,65 @@
#include "wmfs.h"
/* local function definition */
static void conf_section(void (*)(char*), char *, char *);
func_name_list_t tmp_func_list[] =
{
{"spawn", uicb_spawn },
{"client_kill", uicb_client_kill },
{"client_prev", uicb_client_prev },
{"client_next", uicb_client_next },
{"client_swap_next", uicb_client_swap_next },
{"client_swap_prev", uicb_client_swap_prev },
{"client_screen_next", uicb_client_screen_next },
{"client_screen_prev", uicb_client_screen_prev },
{"client_move", uicb_client_move },
{"client_resize", uicb_client_resize },
{"toggle_max", uicb_togglemax },
{"layout_next", uicb_layout_next },
{"layout_prev", uicb_layout_prev },
{"tag", uicb_tag },
{"tag_next", uicb_tag_next },
{"tag_prev", uicb_tag_prev },
{"tag_transfert", uicb_tagtransfert },
{"set_mwfact", uicb_set_mwfact },
{"set_nmaster", uicb_set_nmaster },
{"quit", uicb_quit },
{"toggle_infobar_position", uicb_infobar_togglepos },
{"toggle_resizehint", uicb_toggle_resizehint },
{"mouse_move", uicb_mouse_move },
{"mouse_resize", uicb_mouse_resize },
{"client_raise", uicb_client_raise },
{"toggle_free", uicb_togglefree },
{"toggle_abovefc", uicb_toggle_abovefc },
{"screen_select", uicb_screen_select },
{"screen_next", uicb_screen_next },
{"screen_prev", uicb_screen_prev },
{"reload", uicb_reload },
{"launcher", uicb_launcher },
{"set_layout", uicb_set_layout },
{"menu", uicb_menu },
{"set_client_layer", uicb_set_client_layer },
{"set_layer", uicb_set_layer }
{"spawn", uicb_spawn },
{"client_kill", uicb_client_kill },
{"client_prev", uicb_client_prev },
{"client_next", uicb_client_next },
{"client_swap_next", uicb_client_swap_next },
{"client_swap_prev", uicb_client_swap_prev },
{"client_screen_next", uicb_client_screen_next },
{"client_screen_prev", uicb_client_screen_prev },
{"client_move", uicb_client_move },
{"client_resize", uicb_client_resize },
{"client_ignore_tag", uicb_client_ignore_tag },
{"toggle_max", uicb_togglemax },
{"layout_next", uicb_layout_next },
{"layout_prev", uicb_layout_prev },
{"tag", uicb_tag },
{"tag_next", uicb_tag_next },
{"tag_prev", uicb_tag_prev },
{"tag_next_visible", uicb_tag_next_visible },
{"tag_prev_visible", uicb_tag_prev_visible },
{"tag_prev_sel", uicb_tag_prev_sel },
{"tag_transfert", uicb_tagtransfert },
{"tag_transfert_next", uicb_tagtransfert_next },
{"tag_transfert_prev", uicb_tagtransfert_prev },
{"tag_urgent", uicb_tag_urgent },
{"tag_toggle_additional", uicb_tag_toggle_additional },
{"tag_swap", uicb_tag_swap },
{"tag_swap_next", uicb_tag_swap_next },
{"tag_swap_prev", uicb_tag_swap_previous },
{"tag_new", uicb_tag_new },
{"tag_del", uicb_tag_del },
{"set_mwfact", uicb_set_mwfact },
{"set_nmaster", uicb_set_nmaster },
{"quit", uicb_quit },
{"toggle_infobar_position", uicb_infobar_togglepos },
{"toggle_resizehint", uicb_toggle_resizehint },
{"mouse_move", uicb_mouse_move },
{"mouse_resize", uicb_mouse_resize },
{"client_raise", uicb_client_raise },
{"toggle_free", uicb_togglefree },
{"toggle_abovefc", uicb_toggle_abovefc },
{"screen_select", uicb_screen_select },
{"screen_next", uicb_screen_next },
{"screen_prev", uicb_screen_prev },
{"screen_prev_sel", uicb_screen_prev_sel},
{"reload", uicb_reload },
{"launcher", uicb_launcher },
{"set_layout", uicb_set_layout },
{"menu", uicb_menu },
{"set_client_layer", uicb_set_client_layer },
{"set_layer", uicb_set_layer },
{"ignore_next_client_rules", uicb_ignore_next_client_rules },
{"check_max", uicb_checkmax },
{"check_free", uicb_checkfree },
{"check_layout", uicb_checklayout },
{"clientlist", uicb_clientlist },
{"check_clist", uicb_checkclist },
{"toggle_tagautohide", uicb_toggle_tagautohide }
};
key_name_list_t key_list[] =
@@ -87,6 +103,7 @@ key_name_list_t key_list[] =
{"Mod3", Mod3Mask },
{"Mod4", Mod4Mask },
{"Super", Mod4Mask },
{"Home", Mod4Mask },
{"Mod5", Mod5Mask },
{NULL, NoSymbol }
};
@@ -106,42 +123,38 @@ name_to_uint_t mouse_button_list[] =
};
void
mouse_section(MouseBinding mb[], char *src, int ns)
mouse_section(MouseBinding mb[], struct conf_sec **sec)
{
int i;
char *tmp;
int n;
for(i = 0; i < ns; ++i)
for (n = 0; sec[n]; n++)
{
tmp = get_nsec(src, "mouse", i);
cfg_set_sauv(tmp);
mb[i].tag = get_opt(tmp, "-1", "tag").num;
mb[i].screen = get_opt(tmp, "-1", "screen").num;
mb[i].button = char_to_button(get_opt(tmp, "1", "button").str, mouse_button_list);
mb[i].func = name_to_func(get_opt(tmp, "", "func").str, func_list);
mb[i].cmd = get_opt(tmp, "", "cmd").str;
cfg_set_sauv(src);
mb[n].tag = fetch_opt_first(sec[n], "-1", "tag").num;
mb[n].screen = fetch_opt_first(sec[n], "-1", "screen").num;
mb[n].button = char_to_button(fetch_opt_first(sec[n], "1", "button").str, mouse_button_list);
mb[n].func = name_to_func(fetch_opt_first(sec[n], "", "func").str, func_list);
mb[n].cmd = fetch_opt_first(sec[n], "", "cmd").str;
}
return;
}
void
conf_misc_section(char *src)
conf_misc_section(void)
{
int pad = 12;
struct conf_sec *sec;
cfg_set_sauv(src);
sec = fetch_section_first(NULL, "misc");
conf.font = get_opt(src, "sans-9", "font").str;
conf.raisefocus = get_opt(src, "false", "raisefocus").bool;
conf.raiseswitch = get_opt(src, "false", "raiseswitch").bool;
conf.focus_fmouse = get_opt(src, "true", "focus_follow_mouse").bool;
conf.status_timing = get_opt(src, "1", "status_timing").num;
pad = get_opt(src, "12", "pad").num;
conf.font = fetch_opt_first(sec, "sans-9", "font").str;
conf.raisefocus = fetch_opt_first(sec, "false", "raisefocus").bool;
conf.raiseswitch = fetch_opt_first(sec, "false", "raiseswitch").bool;
conf.focus_fmouse = fetch_opt_first(sec, "true", "focus_follow_mouse").bool;
conf.focus_pclick = fetch_opt_first(sec, "true", "focus_pointer_click").bool;
conf.status_timing = fetch_opt_first(sec, "1", "status_timing").num;
conf.status_path = fetch_opt_first(sec, "", "status_path").str;
conf.autostart_path = fetch_opt_first(sec, "", "autostart_path").str;
conf.autostart_command = fetch_opt_first(sec, "", "autostart_command").str;
pad = fetch_opt_first(sec, "12", "pad").num;
if(pad > 24 || pad < 1)
{
@@ -152,7 +165,7 @@ conf_misc_section(char *src)
conf.pad = pad;
if(conf.status_timing <= 0)
if(conf.status_timing < 0)
{
warnx("configuration : status_timing value (%d) incorrect.", conf.status_timing);
conf.status_timing = 1;
@@ -162,144 +175,194 @@ conf_misc_section(char *src)
}
void
conf_bar_section(char *src)
conf_bar_section(void)
{
cfg_set_sauv(src);
struct conf_sec *bar, **mouse, *selbar;
char *barbg;
conf.border.bar = get_opt(src, "false", "border").bool;
conf.bars.height = get_opt(src, "-1", "height").num;
conf.colors.bar = getcolor(get_opt(src, "#000000", "bg").str);
conf.colors.text = get_opt(src, "#ffffff", "fg").str;
bar = fetch_section_first(NULL, "bar");
if((conf.bars.nmouse = get_size_sec(src, "mouse")))
conf.border.bar = fetch_opt_first(bar, "false", "border").bool;
conf.bars.height = fetch_opt_first(bar, "-1", "height").num;
conf.colors.bar = getcolor((barbg = fetch_opt_first(bar, "#000000", "bg").str));
conf.colors.text = fetch_opt_first(bar, "#ffffff", "fg").str;
mouse = fetch_section(bar, "mouse");
if ((conf.bars.nmouse = fetch_section_count(mouse)) > 0)
{
conf.bars.mouse = emalloc(conf.bars.nmouse, sizeof(MouseBinding));
mouse_section(conf.bars.mouse, src, conf.bars.nmouse);
mouse_section(conf.bars.mouse, mouse);
}
free(mouse);
selbar = fetch_section_first(bar, "selbar");
conf.bars.selbar = selbar ? True : False;
conf.selbar.bg = getcolor(fetch_opt_first(selbar, barbg, "bg").str);
conf.selbar.fg = fetch_opt_first(selbar, conf.colors.text, "fg").str;
conf.selbar.maxlenght = fetch_opt_first(selbar, "-1", "max_lenght").num;
mouse = fetch_section(selbar, "mouse");
if ((conf.selbar.nmouse = fetch_section_count(mouse)))
{
conf.selbar.mouse = emalloc(conf.selbar.nmouse, sizeof(MouseBinding));
mouse_section(conf.selbar.mouse, mouse);
}
free(mouse);
free(barbg);
return;
}
void
conf_root_section(char *src)
conf_root_section(void)
{
cfg_set_sauv(src);
struct conf_sec *root, **mouse;
conf.root.background_command = get_opt(src, "", "background_command").str;
root = fetch_section_first(NULL, "root");
if((conf.root.nmouse = get_size_sec(src, "mouse")))
conf.root.background_command = fetch_opt_first(root, "", "background_command").str;
mouse = fetch_section(root, "mouse");
if ((conf.root.nmouse = fetch_section_count(mouse)) > 0)
{
conf.root.mouse = emalloc(conf.root.nmouse, sizeof(MouseBinding));
mouse_section(conf.root.mouse, src, conf.root.nmouse);
mouse_section(conf.root.mouse, mouse);
}
free(mouse);
return;
}
void
conf_client_section(char *src)
conf_client_section(void)
{
int i, j, d;
char *tmp, *tmp2, *tmp3, *p;
opt_type *buf;
int i, j;
char *flags, *p;
struct conf_sec *sec, **mouse, *titlebar, **button, **line;
struct opt_type *opt;
/* Client misc */
cfg_set_sauv(src);
sec = fetch_section_first(NULL, "client");
conf.client.borderheight = (get_opt(src, "1", "border_height").num) ? get_opt(src, "1", "border_height").num : 1;
conf.client.border_shadow = get_opt(src, "false", "border_shadow").bool;
conf.client.place_at_mouse = get_opt(src, "false", "place_at_mouse").bool;
conf.client.bordernormal = getcolor(get_opt(src, "#000000", "border_normal").str);
conf.client.borderfocus = getcolor(get_opt(src, "#ffffff", "border_focus").str);
conf.client.resizecorner_normal = getcolor(get_opt(src, "#222222", "resize_corner_normal").str);
conf.client.resizecorner_focus = getcolor(get_opt(src, "#DDDDDD", "resize_corner_focus").str);
conf.client.mod |= char_to_modkey(get_opt(src, "Alt", "modifier").str, key_list);
conf.client.set_new_win_master = get_opt(src, "true", "set_new_win_master").bool;
conf.client_round = fetch_opt_first(sec, "true", "client_round").bool;
if((conf.client.nmouse = get_size_sec(src, "mouse")))
if ((conf.client.borderheight = fetch_opt_first(sec, "1", "border_height").num) < 1)
conf.client.borderheight = 1;
conf.client.border_shadow = fetch_opt_first(sec, "false", "border_shadow").bool;
conf.client.place_at_mouse = fetch_opt_first(sec, "false", "place_at_mouse").bool;
conf.client.bordernormal = getcolor(fetch_opt_first(sec, "#000000", "border_normal").str);
conf.client.borderfocus = getcolor(fetch_opt_first(sec, "#ffffff", "border_focus").str);
conf.client.resizecorner_normal = getcolor(fetch_opt_first(sec, "#222222", "resize_corner_normal").str);
conf.client.resizecorner_focus = getcolor(fetch_opt_first(sec, "#DDDDDD", "resize_corner_focus").str);
conf.client.mod |= char_to_modkey(fetch_opt_first(sec, "Alt", "modifier").str, key_list);
conf.client.set_new_win_master = fetch_opt_first(sec, "true", "set_new_win_master").bool;
mouse = fetch_section(sec, "mouse");
if((conf.client.nmouse = fetch_section_count(mouse)) > 0)
{
conf.client.mouse = emalloc(conf.client.nmouse, sizeof(MouseBinding));
mouse_section(conf.client.mouse, src, conf.client.nmouse);
mouse_section(conf.client.mouse, mouse);
}
/* Titlebar part {{ */
tmp = get_sec(src, "titlebar");
cfg_set_sauv(tmp);
free(mouse);
conf.titlebar.height = get_opt(tmp, "0", "height").num;
conf.titlebar.fg_normal = get_opt(tmp, "#ffffff", "fg_normal").str;
conf.titlebar.fg_focus = get_opt(tmp, "#000000", "fg_focus").str;
titlebar = fetch_section_first(sec, "titlebar");
/* Stipple */
conf.titlebar.stipple.active = get_opt(tmp, "false", "stipple").bool;
conf.titlebar.height = fetch_opt_first(titlebar, "0", "height").num;
conf.titlebar.fg_normal = fetch_opt_first(titlebar, "#ffffff", "fg_normal").str;
conf.titlebar.fg_focus = fetch_opt_first(titlebar, "#000000", "fg_focus").str;
if(!strcmp((p = get_opt(tmp, "-1", "stipple_normal").str), "-1"))
conf.titlebar.stipple.active = fetch_opt_first(titlebar, "false", "stipple").bool;
if(!strcmp((p = fetch_opt_first(titlebar, "-1", "stipple_normal").str), "-1"))
conf.titlebar.stipple.colors.normal = getcolor(conf.titlebar.fg_normal);
else
conf.titlebar.stipple.colors.normal = getcolor(p);
if(!strcmp((p = get_opt(tmp, "-1", "stipple_focus").str), "-1"))
if(!strcmp((p = fetch_opt_first(titlebar, "-1", "stipple_focus").str), "-1"))
conf.titlebar.stipple.colors.focus = getcolor(conf.titlebar.fg_focus);
else
conf.titlebar.stipple.colors.focus = getcolor(p);
if((conf.titlebar.nmouse = get_size_sec(tmp, "mouse")))
mouse = fetch_section(titlebar, "mouse");
if((conf.titlebar.nmouse = fetch_section_count(mouse)) > 0)
{
conf.titlebar.mouse = emalloc(conf.titlebar.nmouse, sizeof(MouseBinding));
mouse_section(conf.titlebar.mouse, tmp, conf.titlebar.nmouse);
mouse_section(conf.titlebar.mouse, mouse);
}
free(mouse);
/* Multi button part */
if((conf.titlebar.nbutton = get_size_sec(tmp, "button")))
button = fetch_section(titlebar, "button");
if((conf.titlebar.nbutton = fetch_section_count(button)) > 0)
{
conf.titlebar.button = emalloc(conf.titlebar.nbutton, sizeof(Button));
for(i = 0; i < conf.titlebar.nbutton; ++i)
{
tmp2 = get_nsec(tmp, "button", i);
flags = fetch_opt_first(button[i], "none", "flags").str;
cfg_set_sauv(tmp2);
conf.titlebar.button[i].flags = 0;
if(strstr(flags, "free"))
conf.titlebar.button[i].flags |= FreeFlag;
if(strstr(flags, "max"))
conf.titlebar.button[i].flags |= MaxFlag;
if(strstr(flags, "tile"))
conf.titlebar.button[i].flags |= TileFlag;
/* Multi mouse section */
if((conf.titlebar.button[i].nmouse = get_size_sec(tmp2, "mouse")))
mouse = fetch_section(button[i], "mouse");
if((conf.titlebar.button[i].nmouse = fetch_section_count(mouse)) > 0)
{
conf.titlebar.button[i].mouse = emalloc(conf.titlebar.button[i].nmouse, sizeof(MouseBinding));
mouse_section(conf.titlebar.button[i].mouse, tmp2, conf.titlebar.button[i].nmouse);
mouse_section(conf.titlebar.button[i].mouse, mouse);
}
free(mouse);
/* Multi line section */
if((conf.titlebar.button[i].nlines = get_size_sec(tmp2, "line")))
line = fetch_section(button[i], "line");
if((conf.titlebar.button[i].nlines = fetch_section_count(line)) > 0)
{
conf.titlebar.button[i].linecoord = emalloc(conf.titlebar.button[i].nlines, sizeof(XSegment));
for(j = 0; j < conf.titlebar.button[i].nlines; ++j)
{
tmp3 = get_nsec(tmp2, "line", j);
cfg_set_sauv(tmp3);
buf = get_list_opt(tmp3, "{0, 0, 0, 0}", "coord", &d);
conf.titlebar.button[i].linecoord[j].x1 = buf[0].num;
conf.titlebar.button[i].linecoord[j].y1 = buf[1].num;
conf.titlebar.button[i].linecoord[j].x2 = buf[2].num;
conf.titlebar.button[i].linecoord[j].y2 = buf[3].num;
cfg_set_sauv(tmp2);
opt = fetch_opt(line[j], "0", "coord");
conf.titlebar.button[i].linecoord[j].x1 = opt[0].num;
conf.titlebar.button[i].linecoord[j].y1 = opt[1].num;
conf.titlebar.button[i].linecoord[j].x2 = opt[2].num;
conf.titlebar.button[i].linecoord[j].y2 = opt[3].num;
free(opt);
}
}
cfg_set_sauv(tmp);
free(line);
}
}
/* }} */
free(button);
return;
}
void
conf_layout_section(char *src)
conf_layout_section(void)
{
int i;
char *tmp = NULL, *p;
struct conf_sec *layouts, **layout;
/* Set conf.layout NULL for conf reload */
for(i = 0; i < NUM_OF_LAYOUT; ++i)
@@ -308,17 +371,21 @@ conf_layout_section(char *src)
conf.layout[i].func = NULL;
}
cfg_set_sauv(src);
layouts = fetch_section_first(NULL, "layouts");
conf.border.layout = get_opt(src, "false", "border").bool;
conf.colors.layout_fg = get_opt(src, "#ffffff", "fg").str;
conf.colors.layout_bg = getcolor((get_opt(src, "#000000", "bg").str));
conf.border.layout = fetch_opt_first(layouts, "false", "border").bool;
conf.colors.layout_fg = fetch_opt_first(layouts, "#ffffff", "fg").str;
conf.colors.layout_bg = getcolor((fetch_opt_first(layouts, "#000000", "bg").str));
if((tmp = get_opt(src, "menu", "system").str) && !strcmp(tmp, "menu"))
if((tmp = fetch_opt_first(layouts, "menu", "system").str) && !strcmp(tmp, "menu"))
conf.layout_system = True;
conf.nlayout = get_size_sec(src, "layout");
if((tmp = fetch_opt_first(layouts, "right", "placement").str) && !strcmp(tmp, "left"))
conf.layout_placement = True;
layout = fetch_section(layouts, "layout");
conf.nlayout = fetch_section_count(layout);
if(conf.nlayout > NUM_OF_LAYOUT || !(conf.nlayout))
{
@@ -343,71 +410,89 @@ conf_layout_section(char *src)
{
for(i = 0; i < conf.nlayout; ++i)
{
tmp = get_nsec(src, "layout", i);
cfg_set_sauv(tmp);
if(!name_to_func((p = get_opt(tmp, "tile", "type").str), layout_list))
if(!name_to_func((p = fetch_opt_first(layout[i], "tile", "type").str), layout_list))
warnx("configuration : Unknown Layout type : \"%s\".", p);
else
{
if(conf.layout_system && conf.nlayout > 1)
menu_new_item(&menulayout.item[i], get_opt(tmp, "", "symbol").str,
{
menu_new_item(&menulayout.item[i], fetch_opt_first(layout[i], "", "symbol").str,
uicb_set_layout, p);
conf.layout[i].symbol = get_opt(tmp, "TILE (default)", "symbol").str;
conf.layout[i].func = name_to_func(p, layout_list);
}
menulayout.item[i].check = name_to_func("check_layout", func_list);
}
cfg_set_sauv(src);
conf.layout[i].symbol = fetch_opt_first(layout[i], "TILE (default)", "symbol").str;
conf.layout[i].func = name_to_func(p, layout_list);
conf.layout[i].type = p;
}
}
}
free(layout);
return;
}
void
conf_tag_section(char *src)
conf_tag_section(void)
{
int i, j, k, l = 0, m, n, sc;
char *cfgtmp, *tmp;
opt_type *buf;
int i, j, k, l = 0, m, n, sc, count;
char *tmp;
struct conf_sec *sec, **tag, **mouse;
struct opt_type *opt;
/* If there is no tag in the conf or more than
* MAXTAG (32) print an error and create only one.
*/
Tag default_tag = { "WMFS", NULL, 0, 1,
0.50, 1, False, False, False, IB_Top,
layout_name_to_struct(conf.layout, "tile_right", conf.nlayout, layout_list) };
0.50, 1, False, False, False, False, IB_Top,
layout_name_to_struct(conf.layout, "tile_right", conf.nlayout, layout_list),
0, NULL, 0 };
cfg_set_sauv(src);
sec = fetch_section_first(NULL, "tags");
conf.tag_round = get_opt(src, "false", "tag_round").bool;
conf.colors.tagselfg = get_opt(src, "#ffffff", "sel_fg").str;
conf.colors.tagselbg = getcolor(get_opt(src, "#000000", "sel_bg").str);
conf.colors.tag_occupied_bg = getcolor(get_opt(src, "#222222", "occupied_bg").str);
conf.border.tag = get_opt(src, "false", "border").bool;
conf.tag_round = fetch_opt_first(sec, "false", "tag_round").bool;
conf.colors.tagselfg = fetch_opt_first(sec, "#ffffff", "sel_fg").str;
conf.colors.tagselbg = getcolor(fetch_opt_first(sec, "#000000", "sel_bg").str);
conf.colors.tagurfg = fetch_opt_first(sec, "#000000", "urgent_fg").str;
conf.colors.tagurbg = getcolor(fetch_opt_first(sec, "#DD1111", "urgent_bg").str);
conf.colors.tag_occupied_bg = getcolor(fetch_opt_first(sec, "#222222", "occupied_bg").str);
conf.border.tag = fetch_opt_first(sec, "false", "border").bool;
conf.tagautohide = fetch_opt_first(sec, "false", "autohide").bool;
/* Mouse button action on tag */
conf.mouse_tag_action[TagSel] =
char_to_button(fetch_opt_first(sec, "1", "mouse_button_tag_sel").str, mouse_button_list);
conf.mouse_tag_action[TagTransfert] =
char_to_button(fetch_opt_first(sec, "2", "mouse_button_tag_transfert").str, mouse_button_list);
conf.mouse_tag_action[TagAdd] =
char_to_button(fetch_opt_first(sec, "3", "mouse_button_tag_add").str, mouse_button_list);
conf.mouse_tag_action[TagNext] =
char_to_button(fetch_opt_first(sec, "4", "mouse_button_tag_next").str, mouse_button_list);
conf.mouse_tag_action[TagPrev] =
char_to_button(fetch_opt_first(sec, "5", "mouse_button_tag_prev").str, mouse_button_list);
sc = screen_count();
/* Alloc all */
conf.ntag = emalloc(sc, sizeof(int));
tags = emalloc(sc, sizeof(Tag*));
seltag = emalloc(sc, sizeof(int));
conf.ntag = emalloc(sc, sizeof(int));
tags = emalloc(sc, sizeof(Tag*));
seltag = emalloc(sc, sizeof(int));
prevseltag = emalloc(sc, sizeof(int));
for(i = 0; i < sc; ++i)
seltag[i] = 1;
tag = fetch_section(sec, "tag");
n = fetch_section_count(tag);
for(i = 0; i < sc; ++i)
tags[i] = emalloc(get_size_sec(src, "tag") + 2, sizeof(Tag));
tags[i] = emalloc(n + 2, sizeof(Tag));
for(i = 0; i < get_size_sec(src, "tag"); ++i)
for(i = 0; i < n; i++)
{
/* printf("%d -> %s\n", i, (cfgtmp = get_nsec(src, "tag", i)));*/
cfgtmp = get_nsec(src, "tag", i);
cfg_set_sauv(cfgtmp);
j = get_opt(cfgtmp, "-1", "screen").num;
j = fetch_opt_first(tag[i], "-1", "screen").num;
if(j < 0 || j > sc - 1)
j = -1;
@@ -417,14 +502,14 @@ conf_tag_section(char *src)
((j == -1) ? ++k : --l))
{
++conf.ntag[k];
tags[k][conf.ntag[k]].name = get_opt(cfgtmp, "", "name").str;
tags[k][conf.ntag[k]].mwfact = get_opt(cfgtmp, "0.65", "mwfact").fnum;
tags[k][conf.ntag[k]].nmaster = get_opt(cfgtmp, "1", "nmaster").num;
tags[k][conf.ntag[k]].resizehint = get_opt(cfgtmp, "false", "resizehint").bool;
tags[k][conf.ntag[k]].abovefc = get_opt(cfgtmp, "false", "abovefc").bool;
tags[k][conf.ntag[k]].name = fetch_opt_first(tag[i], "", "name").str;
tags[k][conf.ntag[k]].mwfact = fetch_opt_first(tag[i], "0.65", "mwfact").fnum;
tags[k][conf.ntag[k]].nmaster = fetch_opt_first(tag[i], "1", "nmaster").num;
tags[k][conf.ntag[k]].resizehint = fetch_opt_first(tag[i], "false", "resizehint").bool;
tags[k][conf.ntag[k]].abovefc = fetch_opt_first(tag[i], "false", "abovefc").bool;
tags[k][conf.ntag[k]].layers = 1;
tmp = _strdup(get_opt(cfgtmp, "top", "infobar_position").str);
tmp = fetch_opt_first(tag[i], "top", "infobar_position").str;
if(!strcmp(tmp ,"none") || !strcmp(tmp, "hide") || !strcmp(tmp, "hidden"))
tags[k][conf.ntag[k]].barpos = IB_Hide;
@@ -434,23 +519,35 @@ conf_tag_section(char *src)
tags[k][conf.ntag[k]].barpos = IB_Top;
tags[k][conf.ntag[k]].layout = layout_name_to_struct(conf.layout,
get_opt(cfgtmp, "tile_right", "layout").str,
fetch_opt_first(tag[i], "tile_right", "layout").str,
conf.nlayout,
layout_list);
/* Clients list */
buf = get_list_opt(cfgtmp, "", "clients", &n);
if(n)
opt = fetch_opt(tag[i], "", "clients");
if ((count = fetch_opt_count(opt)))
{
tags[k][conf.ntag[k]].nclients = n;
tags[k][conf.ntag[k]].clients = emalloc(n, sizeof(char *));
for(m = 0; m < n; ++m)
tags[k][conf.ntag[k]].clients[m] = (buf[m].str) ? buf[m].str : NULL;
tags[k][conf.ntag[k]].nclients = count;
tags[k][conf.ntag[k]].clients = emalloc(count, sizeof(char *));
for(m = 0; m < count; ++m)
tags[k][conf.ntag[k]].clients[m] = opt[m].str;
}
free(opt);
/* Multi mouse sections */
mouse = fetch_section(tag[i], "mouse");
if((tags[k][conf.ntag[k]].nmouse = fetch_section_count(mouse)))
{
tags[k][conf.ntag[k]].mouse = emalloc(tags[k][conf.ntag[k]].nmouse, sizeof(MouseBinding));
mouse_section(tags[k][conf.ntag[k]].mouse, mouse);
}
free(mouse);
}
l = 0;
cfg_set_sauv(src);
}
for(i = 0; i < sc; ++i)
@@ -461,126 +558,134 @@ conf_tag_section(char *src)
tags[i][1] = default_tag;
}
free(tag);
return;
}
void
conf_menu_section(char *src)
conf_menu_section(void)
{
char *tmp, *tmp2;
char *tmp2;
int i, j;
struct conf_sec *menu, **set_menu, **item;
cfg_set_sauv(src);
menu = fetch_section_first(NULL, "menu");
CHECK((conf.nmenu = get_size_sec(src, "set_menu")));
set_menu = fetch_section(menu, "set_menu");
CHECK((conf.nmenu = fetch_section_count(set_menu)));
conf.menu = calloc(conf.nmenu, sizeof(Menu));
for(i = 0; i < conf.nmenu; ++i)
{
tmp = get_nsec(src, "set_menu", i);
cfg_set_sauv(tmp);
conf.menu[i].name = get_opt(tmp, "menu_wname", "name").str;
conf.menu[i].name = fetch_opt_first(set_menu[i], "menu_wname", "name").str;
if(!(conf.menu[i].place_at_mouse = get_opt(tmp, "true", "place_at_mouse").bool))
if(!(conf.menu[i].place_at_mouse = fetch_opt_first(set_menu[i], "true", "place_at_mouse").bool))
{
conf.menu[i].x = get_opt(tmp, "0", "x").num;
conf.menu[i].y = get_opt(tmp, "0", "y").num;
conf.menu[i].x = fetch_opt_first(set_menu[i], "0", "x").num;
conf.menu[i].y = fetch_opt_first(set_menu[i], "0", "y").num;
}
conf.menu[i].colors.focus.bg = getcolor(get_opt(tmp, "#000000", "bg_focus").str);
conf.menu[i].colors.focus.fg = get_opt(tmp, "#ffffff", "fg_focus").str;
conf.menu[i].colors.normal.bg = getcolor(get_opt(tmp, "#000000", "bg_normal").str);
conf.menu[i].colors.normal.fg = get_opt(tmp, "#ffffff", "fg_normal").str;
tmp2 = fetch_opt_first(set_menu[i], "center", "align").str;
if((conf.menu[i].nitem = get_size_sec(tmp, "item")))
if(!strcmp(tmp2 ,"left"))
conf.menu[i].align = MA_Left;
else if(!strcmp(tmp2, "right"))
conf.menu[i].align = MA_Right;
else
conf.menu[i].align = MA_Center;
conf.menu[i].colors.focus.bg = getcolor(fetch_opt_first(set_menu[i], "#000000", "bg_focus").str);
conf.menu[i].colors.focus.fg = fetch_opt_first(set_menu[i], "#ffffff", "fg_focus").str;
conf.menu[i].colors.normal.bg = getcolor(fetch_opt_first(set_menu[i], "#000000", "bg_normal").str);
conf.menu[i].colors.normal.fg = fetch_opt_first(set_menu[i], "#ffffff", "fg_normal").str;
item = fetch_section(set_menu[i], "item");
if((conf.menu[i].nitem = fetch_section_count(item)))
{
conf.menu[i].item = emalloc(conf.menu[i].nitem, sizeof(MenuItem));
for(j = 0; j < get_size_sec(tmp, "item"); ++j)
for(j = 0; j < conf.menu[i].nitem; ++j)
{
tmp2 = get_nsec(tmp, "item", j);
cfg_set_sauv(tmp2);
conf.menu[i].item[j].name = get_opt(tmp2, "item_wname", "name").str;
conf.menu[i].item[j].func = name_to_func(get_opt(tmp2, "", "func").str, func_list);
conf.menu[i].item[j].cmd = (!get_opt(tmp2, "", "cmd").str) ? NULL : get_opt(tmp2, "", "cmd").str;
cfg_set_sauv(tmp);
conf.menu[i].item[j].name = fetch_opt_first(item[j], "item_wname", "name").str;
conf.menu[i].item[j].func = name_to_func(fetch_opt_first(item[j], "", "func").str, func_list);
conf.menu[i].item[j].cmd = fetch_opt_first(item[j], "", "cmd").str;
conf.menu[i].item[j].check = name_to_func(fetch_opt_first(item[j], "", "check").str, func_list);
conf.menu[i].item[j].submenu = fetch_opt_first(item[j], "", "submenu").str;
}
}
cfg_set_sauv(src);
free(item);
}
free(set_menu);
return;
}
void
conf_launcher_section(char *src)
conf_launcher_section(void)
{
int i;
char *tmp;
struct conf_sec *launcher, **set_launcher;
cfg_set_sauv(src);
launcher = fetch_section_first(NULL, "launcher");
set_launcher = fetch_section(launcher, "set_launcher");
CHECK((conf.nlauncher = get_size_sec(src, "set_launcher")));
CHECK((conf.nlauncher = fetch_section_count(set_launcher)));
conf.launcher = emalloc(conf.nlauncher, sizeof(Launcher));
for(i = 0; i < conf.nlauncher; ++i)
{
tmp = get_nsec(src, "set_launcher", i);
cfg_set_sauv(tmp);
conf.launcher[i].name = get_opt(tmp, "launcher", "name").str;
conf.launcher[i].prompt = get_opt(tmp, "Exec:", "prompt").str;
conf.launcher[i].command = get_opt(tmp, "exec", "command").str;
cfg_set_sauv(src);
conf.launcher[i].name = fetch_opt_first(set_launcher[i], "launcher", "name").str;
conf.launcher[i].prompt = fetch_opt_first(set_launcher[i], "Exec:", "prompt").str;
conf.launcher[i].command = fetch_opt_first(set_launcher[i], "exec", "command").str;
conf.launcher[i].nhisto = 1;
}
free(set_launcher);
return;
}
void
conf_keybind_section(char *src)
conf_keybind_section(void)
{
int i, j, n = 0;
char *tmp;
opt_type *buf;
int i, j;
struct conf_sec *sec, **ks;
struct opt_type *opt;
cfg_set_sauv(src);
sec = fetch_section_first(NULL, "keys");
ks = fetch_section(sec, "key");
conf.nkeybind = get_size_sec(src, "key");
conf.nkeybind = fetch_section_count(ks);
keys = emalloc(conf.nkeybind, sizeof(Key));
for(i = 0; i < conf.nkeybind; ++i)
{
tmp = get_nsec(src, "key", i);
opt = fetch_opt(ks[i], "", "mod");
cfg_set_sauv(tmp);
for(j = 0; j < fetch_opt_count(opt); ++j)
keys[i].mod |= char_to_modkey(opt[j].str, key_list);
buf = get_list_opt(tmp, "", "mod", &n);
free(opt);
for(j = 0; j < n; ++j)
keys[i].mod |= char_to_modkey(buf[j].str, key_list);
keys[i].keysym = XStringToKeysym(fetch_opt_first(ks[i], "None", "key").str);
keys[i].keysym = XStringToKeysym(get_opt(tmp, "None", "key").str);
keys[i].func = name_to_func(get_opt(tmp, "", "func").str, func_list);
keys[i].func = name_to_func(fetch_opt_first(ks[i], "", "func").str, func_list);
if(keys[i].func == NULL)
{
warnx("configuration : Unknown Function \"%s\".", get_opt(tmp, "", "func").str);
warnx("configuration : Unknown Function \"%s\".", fetch_opt_first(ks[i], "", "func").str);
keys[i].func = uicb_spawn;
}
keys[i].cmd = (!get_opt(tmp, "", "cmd").str) ? NULL : get_opt(tmp, "", "cmd").str;
cfg_set_sauv(src);
keys[i].cmd = fetch_opt_first(ks[i], "", "cmd").str;
}
free(ks);
return;
}
@@ -589,46 +694,31 @@ conf_keybind_section(char *src)
void
init_conf(void)
{
char *file;
if(!(file = file_to_str(conf.confpath)))
if (get_conf(conf.confpath) == -1)
{
warnx("parsing configuration file (%s) failed.", conf.confpath);
sprintf(conf.confpath, "%s/wmfs/wmfsrc", XDG_CONFIG_DIR);
warnx("Use the default configuration (%s).", conf.confpath);
file = file_to_str(conf.confpath);
if (get_conf(conf.confpath) == -1)
errx(1, "parsing configuration file (%s) failed.", conf.confpath);
}
/* Set func_list */
func_list = emalloc(LEN(tmp_func_list), sizeof(func_name_list_t));
memcpy(func_list, tmp_func_list, LEN(tmp_func_list) * sizeof(func_name_list_t));
conf_section(conf_misc_section, file, "misc");
conf_section(conf_bar_section, file, "bar");
conf_section(conf_root_section, file, "root");
conf_section(conf_client_section, file, "client");
conf_section(conf_layout_section, file, "layouts");
conf_section(conf_tag_section, file, "tags");
conf_section(conf_menu_section, file, "menu");
conf_section(conf_launcher_section, file, "launcher");
conf_section(conf_keybind_section, file, "keys");
conf_misc_section();
conf_bar_section();
conf_root_section();
conf_client_section();
conf_layout_section();
conf_tag_section();
conf_menu_section();
conf_launcher_section();
conf_keybind_section();
free(file);
return;
}
/** Simple wrapper for calling functions and free pointer
*/
static void
conf_section(void (*func)(char*), char *src, char *name)
{
char *sec;
sec = get_sec(src, name);
func(sec);
IFREE(sec);
print_unused(NULL);
return;
}

View File

@@ -41,7 +41,10 @@
#define WMFS_COMPILE_FLAGS "@WMFS_COMPILE_FLAGS@"
#define WMFS_LINKED_LIBS "@WMFS_LINKED_LIBS@"
#define XDG_CONFIG_DIR "@XDG_CONFIG_DIR@"
/* Optional dependencies */
@WMFS_HAVE_XINERAMA@
@WMFS_HAVE_XRANDR@
@WMFS_HAVE_IMLIB@
#endif /* CONFIG_H */

View File

@@ -1,289 +0,0 @@
/*
* confparse.c
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "confparse.h"
char*
file_to_str(char *path)
{
char *buf, *ret, *p, *c;
int fd, i;
struct stat st;
Bool is_char = False;
if (!path)
return NULL;
if (!(fd = open(path, O_RDONLY)))
{
warn("%s", path);
return NULL;
}
/* Get the file size */
stat(path, &st);
/* Bufferize file */
if((buf = (char*)mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, SEEK_SET)) == (char*) MAP_FAILED)
return NULL;
/* Copy buffer without comments in return value */
ret = emalloc(strlen(buf) + 1, sizeof(char));
for(p = buf, i = 0; *p != '\0'; p++)
{
if(!is_char && (c = strchr("\"'", *p)))
is_char = !is_char;
else if (is_char && *p == *c)
is_char = !is_char;
if(*p == COMMENT_CHAR && !is_char)
{
if(!(p = strchr(p, '\n')))
break;
ret[i++] = '\n';
}
else
ret[i++] = *p;
}
ret[i++] = '\0';
/* Unmap buffer, thanks linkdd. */
munmap(buf, st.st_size);
close(fd);
warnx("%s read.", path);
return ret;
}
char*
get_sec(char *src, char *name)
{
char *ret = NULL, *start, *end, *p;
char **sec;
size_t len;
if(!src)
return NULL;
if(!name)
return src;
sec = secname(name);
len = strlen(sec[SecStart]);
/* Find start section pointer */
for(start = src; *start != '\0'; start++)
{
if( (p = strchr("\"'", *start)) )
while (*(++start) && *start != *p);
if(!strncmp(start, sec[SecStart], len))
break;
}
if(*start != '\0')
{
/* Here is_char == False */
start += len;
/* Find end section pointer */
for(end = start; *end != '\0'; end++)
{
if( (p = strchr("\"'", *start)) )
while (*(++start) && *start != *p);
if(!strncmp(end, sec[SecEnd], len+1))
break;
}
/* Allocate and set ret */
if(end != '\0')
{
len = end - start;
ret = emalloc(len + 1, sizeof(char));
memcpy(ret, start, len);
ret[len] = '\0';
}
}
free_secname(sec);
return ret;
}
char*
get_nsec(char *src, char *name, int n)
{
int i;
char *ret, *buf, **sec;
if(!src || !strlen(src))
return NULL;
if(!name)
return src;
if(!n)
return get_sec(src, name);
sec = secname(name);
buf = _strdup(sauv_delimc);
for(i = 0; i < n && (buf = strstr(buf, sec[SecStart])); ++i, buf += strlen(sec[SecStart]));
ret = get_sec(src + strlen(src) - strlen(buf), name);
free_secname(sec);
return ret;
}
int
get_size_sec(char *src, char *name)
{
int ret;
char **sec, *buf;
if(!src || !name)
return 0;
sec = secname(name);
buf = _strdup(sauv_secc);
for(ret = 0; (buf = strstr(buf, sec[SecStart])); ++ret, buf += strlen(sec[SecStart]));
free_secname(sec);
return ret;
}
opt_type
get_opt(char *src, char *def, char *name)
{
int i;
char *p = NULL, *p2 = NULL;
opt_type ret = null_opt_type;
if(!src || !name)
return (def) ? str_to_opt(def) : ret;
if((p = opt_srch(sauv_secc, name)))
{
for(i = 0; p[i] && p[i] != '\n'; ++i);
p[i] = '\0';
p2 = _strdup(p + strlen(name));
if((p = strchr(p, '=')) && !is_in_delimiter(p, 0))
{
for(i = 0; p2[i] && p2[i] != '='; ++i);
p2[i] = '\0';
/* Check if there is anything else that spaces
* between option name and '=' */
for(i = 0; i < strlen(p2); ++i)
if(p2[i] != ' ')
{
warnx("Configuration warning: Missing '=' after option: '%s'"
" and before expression: '%s'\n", name, p2);
return str_to_opt(def);
}
ret = str_to_opt(clean_value(++p));
}
}
if(!ret.str)
ret = str_to_opt(def);
return ret;
}
/* option = {val1, val2, val3} */
opt_type*
get_list_opt(char *src, char *def, char *name, int *n)
{
int i, j;
char *p, *p2;
opt_type *ret;
if(!src || !name)
return NULL;
*n = 0;
if(!(p = get_opt(src, def, name).str))
return NULL;
for(i = 0; p[i] && (p[i] != LIST_DEL_E || is_in_delimiter(p, i)); ++i);
p[i + 1] = '\0';
/* Syntax of list {val1, val2, ..., valx} */
if(*p != LIST_DEL_S || *(p + strlen(p) - 1) != LIST_DEL_E)
return NULL;
/* Erase ( ) */
++p;
*(p + strlen(p) - 1) = '\0';
/* > 1 value in list */
if(strchr(p, ','))
{
/* Count ',' */
for(i = 0, *n = 1; i < strlen(p); ++i)
if(p[i] == ',' && !is_in_delimiter(p, i))
++(*n);
ret = emalloc(*n, sizeof(opt_type));
p2 = _strdup(p);
/* Set all value in return array */
for(i = j = 0; i < *n; ++i, p2 += ++j)
{
for(j = 0; j < strlen(p2) && (p2[j] != ',' || is_in_delimiter(p2, j)); ++j);
p2[j] = '\0';
ret[i] = str_to_opt(clean_value(p2));
}
}
else
{
ret = emalloc((*n = 1), sizeof(opt_type));
*ret = str_to_opt(clean_value(p));
}
return ret;
}

View File

@@ -1,87 +0,0 @@
/*
* confparse.h
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CONFPARSE_H
#define CONFPARSE_H
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "../wmfs.h"
/* Section delimiter */
#define SEC_DEL_S '['
#define SEC_DEL_E ']'
/* List delimiter */
#define LIST_DEL_S '{'
#define LIST_DEL_E '}'
/* Comment character */
#define COMMENT_CHAR '#'
enum { SecStart, SecEnd, SecLast };
typedef struct
{
long int num;
float fnum;
Bool bool;
char *str;
} opt_type;
/* util.c */
char *erase_delim_content(char *buf);
Bool is_in_delimiter(char *buf, int p);
char *erase_sec_content(char *buf);
char *opt_srch(char *buf, char *opt);
opt_type str_to_opt(char *str);
char *clean_value(char *str);
void cfg_set_sauv(char *str);
char **secname(char *name);
void free_secname(char **secname);
/* confparse.c */
char *file_to_str(char *path);
char *get_sec(char *src, char *name);
char *get_nsec(char *src, char *name, int n);
int get_size_sec(char *src, char *name);
opt_type get_opt(char *src, char *def, char *name);
opt_type *get_list_opt(char *src, char *def, char *name, int *n);
static const opt_type null_opt_type = {0, 0, 0, NULL};
char *sauv_delimc;
char *sauv_secc;
#endif /* CONFPARSE_H */

View File

@@ -1,220 +0,0 @@
/*
* confparse/util.c
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "confparse.h"
char*
erase_delim_content(char *buf)
{
int i, j;
char *str, c;
if(!buf || !(str = _strdup(buf)))
return NULL;
for(i = 0; i < strlen(str); ++i)
if(strchr("\"'", (c = str[i])))
{
for(*(str + (j = i)) = ' '; str[j] && str[j] != c; str[j++] = ' ');
str[j] = ' ';
}
return str;
}
/* Erase all content of all delimiters, put it
* int str, and check if buf[p] is in an delimiter. */
Bool
is_in_delimiter(char *buf, int p)
{
if(*(erase_delim_content(buf) + p) != buf[p])
return True;
return False;
}
char*
erase_sec_content(char *buf)
{
int i, j;
char *p, *str, *name, *ret;
char **sec;
if(!buf || !(str = _strdup(sauv_delimc)))
return NULL;
ret = _strdup(buf);
for(i = 1, name = _strdup(str + i); strchr(str + i, SEC_DEL_S); ++i, name = _strdup(str + i))
{
for(; str[i] && str[i] != SEC_DEL_S; ++i);
for(j = 0; str[i] && str[i] != SEC_DEL_E; name[j++] = str[i++]);
++name;
name[j - 1] = '\0';
if(*name == '/')
continue;
sec = secname(name);
if((p = strstr(str + i, sec[SecEnd])))
for(++i; i < strlen(ret) - strlen(p); ret[i++] = ' ');
else
break;
}
free_secname(sec);
return ret;
}
/* To get the RIGHT name of an option; if option needed is
* pwet and there is tagadapwettagada in the configuration,
* with strstr(), the name will matchs */
char*
opt_srch(char *buf, char *opt)
{
char *p;
if(!buf || !opt)
return NULL;
if((p = strstr(sauv_delimc /*erase_delim_content(buf)*/, opt)))
if((*(p + strlen(opt)) == ' ' || *(p + strlen(opt)) == '=')
&& (*(p - 1) == ' ' || *(p - 1) == '\n' || *(p - 1) == '\t' || !(*(p - 1))))
return _strdup(buf + (strlen(buf) - strlen(p)));
return NULL;
}
opt_type
str_to_opt(char *str)
{
opt_type ret = null_opt_type;
if(!strlen(str))
return ret;
/* Integer */
ret.num = atoi(str);
/* Float */
sscanf(str, "%f", &ret.fnum);
/* Boolean */
if(strstr(str, "true") || strstr(str, "True")
|| strstr(str, "TRUE") || strstr(str, "1"))
ret.bool = True;
/* String */
ret.str = _strdup(str);
return ret;
}
char*
clean_value(char *str)
{
int i;
char c, *p;
if(!str || !(p = _strdup(str)))
return NULL;
/* Remove useless spaces */
for(; *p == ' '; ++p);
for(; *(p + strlen(p) - 1) == ' '; *(p + strlen(p) - 1) = '\0');
/* For string delimiter (" or ') */
if(((c = *p) == '"' || (c = *p) == '\'') && strchr(p + 1, c))
{
for(++p, i = 0; p[i] && p[i] != c; ++i);
p[i] = '\0';
}
return p;
}
void
cfg_set_sauv(char *str)
{
if(!str)
{
sauv_delimc = NULL;
sauv_secc = NULL;
return;
}
sauv_delimc = erase_delim_content(_strdup(str));
sauv_secc = erase_sec_content(_strdup(str));
return;
}
char**
secname(char *name)
{
char **ret = NULL;
if(!name)
return NULL;
ret = emalloc(SecLast, sizeof(char*));
/* Len of name + '[' + ']' + '\0' */
ret[SecStart] = emalloc(strlen(name) + 3, sizeof(char));
/* Len of name + '[' + '/' + ']' + '\0' */
ret[SecEnd] = emalloc(strlen(name) + 4, sizeof(char));
sprintf(ret[SecStart], "%c%s%c", SEC_DEL_S, name, SEC_DEL_E);
sprintf(ret[SecEnd], "%c/%s%c", SEC_DEL_S, name, SEC_DEL_E);
return ret;
}
void
free_secname(char **secname)
{
if(!secname || LEN(secname) != SecLast)
return;
if(secname[SecStart])
free(secname[SecStart]);
if(secname[SecEnd])
free(secname[SecEnd]);
free(secname);
return;
}

View File

@@ -46,6 +46,26 @@ draw_text(Drawable d, int x, int y, char* fg, int pad, char *str)
XftColor xftcolor;
XftDraw *xftd;
if(!str)
return;
/* To draw image everywhere we can draw text */
#ifdef HAVE_IMLIB
char *ostr = NULL;
int i, ni;
ImageAttr im[128];
ostr = _strdup(str);
if(strstr(str, "i["))
{
ni = parse_image_block(im, str);
for(i = 0; i < ni; ++i)
draw_image(d, im[i].x, im[i].y, im[i].w, im[i].h, im[i].name);
}
#endif /* HAVE_IMLIB */
/* Transform X Drawable -> Xft Drawable */
xftd = XftDrawCreate(dpy, d, DefaultVisual(dpy, SCREEN), DefaultColormap(dpy, SCREEN));
@@ -60,6 +80,13 @@ draw_text(Drawable d, int x, int y, char* fg, int pad, char *str)
XftDrawDestroy(xftd);
#ifdef HAVE_IMLIB
if(strstr(ostr, "i["))
strcpy(str, ostr);
IFREE(ostr);
#endif /* HAVE_IMLIB */
return;
}
@@ -82,20 +109,106 @@ draw_rectangle(Drawable dr, int x, int y, uint w, uint h, uint color)
return;
}
/** Draw a Graph in a drawable
* \param dr Drawable
* \param x X position
* \param y Y position
* \param w Width
* \param h Height
* \param color Color of the graph
* \param data Array of bytes that will be draw
*/
void
draw_graph(Drawable dr, int x, int y, uint w, uint h, uint color, char *data)
{
int i;
XSetForeground(dpy, gc, color);
for(i = 0; i < w; ++i)
{
XRectangle r = { (x + i), (y + h - data[i]), 1, data[i] };
XFillRectangles(dpy, dr, gc, &r, 1);
}
return;
}
#ifdef HAVE_IMLIB
/** Draw an image in a drawable
* \param dr Drawable
* \param x X position
* \param y Y position
* \param name Path of the image
*/
void
draw_image(Drawable dr, int x, int y, int w, int h, char *name)
{
Imlib_Image image;
if(!name)
return;
imlib_set_cache_size(2048 * 1024);
imlib_context_set_display(dpy);
imlib_context_set_visual(DefaultVisual(dpy, DefaultScreen(dpy)));
imlib_context_set_colormap(DefaultColormap(dpy, DefaultScreen(dpy)));
imlib_context_set_drawable(dr);
image = imlib_load_image(name);
imlib_context_set_image(image);
if(w <= 0)
w = imlib_image_get_width();
if(h <= 0)
h = imlib_image_get_height();
if(image)
{
imlib_render_image_on_drawable_at_size(x, y, w, h);
imlib_free_image();
}
else
warnx("Can't draw image: '%s'", name);
return;
}
#endif /* HAVE_IMLIB */
/** Calculates the text's size relatively to the font
* \param text Text string
* \return final text width
*/
ushort
textw(const char *text)
textw(char *text)
{
XGlyphInfo gl;
if(!text)
return 0;
#ifdef HAVE_IMLIB
char *ostr = NULL;
ImageAttr im[128];
ostr = _strdup(text);
if(strstr(text, "i["))
parse_image_block(im, text);
#endif /* HAVE_IMLIB */
XftTextExtentsUtf8(dpy, font, (FcChar8 *)text, strlen(text), &gl);
#ifdef HAVE_IMLIB
if(strstr(ostr, "i["))
strcpy(text, ostr);
IFREE(ostr);
#endif /* HAVE_IMLIB */
return gl.width + font->descent;
}

View File

@@ -49,6 +49,8 @@ buttonpress(XButtonEvent *ev)
{
client_focus(c);
client_raise(c);
return;
}
/* Titlebar */
@@ -96,16 +98,36 @@ buttonpress(XButtonEvent *ev)
if(conf.bars.mouse[j].func)
conf.bars.mouse[j].func(conf.bars.mouse[j].cmd);
/* Selbar */
if(conf.bars.selbar && ev->window == infobar[selscreen].selbar->win)
for(i = 0; i < conf.selbar.nmouse; ++i)
if(conf.selbar.mouse[i].tag == seltag[conf.selbar.mouse[i].screen]
|| conf.selbar.mouse[i].tag < 0)
if(ev->button == conf.selbar.mouse[i].button)
if(conf.selbar.mouse[i].func)
conf.selbar.mouse[i].func(conf.selbar.mouse[i].cmd);
/* Tags */
for(i = 1; i < conf.ntag[selscreen] + 1; ++i)
if(ev->window == infobar[selscreen].tags[i]->win)
switch(ev->button)
{
case Button1: tag_set(i); break;
case Button3: tag_transfert(sel, i); break;
case Button4: tag_set(seltag[selscreen] + 1); break;
case Button5: tag_set(seltag[selscreen] - 1); break;
}
{
for(j = 0; j < tags[selscreen][i].nmouse; ++j)
if(ev->button == tags[selscreen][i].mouse[j].button)
if(tags[selscreen][i].mouse[j].func)
tags[selscreen][i].mouse[j].func(tags[selscreen][i].mouse[j].cmd);
/* Mouse button action on tag */
if(ev->button == conf.mouse_tag_action[TagSel])
tag_set(i);
else if(ev->button == conf.mouse_tag_action[TagTransfert])
tag_transfert(sel, i);
else if(ev->button == conf.mouse_tag_action[TagAdd])
tag_additional(selscreen, seltag[selscreen], i);
else if(ev->button == conf.mouse_tag_action[TagNext])
tag_set(seltag[selscreen] + 1);
else if(ev->button == conf.mouse_tag_action[TagPrev])
tag_set(seltag[selscreen] - 1);
}
/* Layout button */
if(ev->window == infobar[selscreen].layout_button->win && conf.nlayout > 1)
@@ -140,7 +162,7 @@ void
clientmessageevent(XClientMessageEvent *ev)
{
Client *c;
int i, mess_t = 0;
int s, i, mess_t = 0;
Atom rt;
int rf;
ulong ir, il;
@@ -151,7 +173,9 @@ clientmessageevent(XClientMessageEvent *ev)
if(ev->format != 32)
return;
for(i = 0; i < net_last + screen_count(); ++i)
s = screen_count();
for(i = 0; i < net_last + s; ++i)
if(net_atom[i] == ev->message_type)
mess_t = i;
@@ -166,7 +190,7 @@ clientmessageevent(XClientMessageEvent *ev)
/* Manage _WMFS_SET_SCREEN */
if(mess_t == wmfs_set_screen
&& ev->data.l[0] >= 0
&& ev->data.l[0] <= screen_count())
&& ev->data.l[0] <= s)
screen_set_sel((int)(ev->data.l[0]));
/* Manage _NET_ACTIVE_WINDOW */
@@ -196,7 +220,7 @@ clientmessageevent(XClientMessageEvent *ev)
if(XGetWindowProperty(dpy, ROOT, net_atom[mess_t], 0, 4096,
False, net_atom[utf8_string], &rt, &rf, &ir, &il, &ret) == Success)
{
infobar_draw_statustext(mess_t - wmfs_statustext, (char*)ret);
statustext_handle(mess_t - wmfs_statustext, (char*)ret);
XFree(ret);
}
}
@@ -233,7 +257,7 @@ clientmessageevent(XClientMessageEvent *ev)
if(mess_t == wmfs_update_status
&& estatus)
spawn(status_path);
spawn(conf.status_path);
return;
}
@@ -349,6 +373,8 @@ expose(XExposeEvent *ev)
barwin_refresh(infobar[sc].bar);
if(ev->window == infobar[sc].layout_button->win)
barwin_refresh(infobar[sc].layout_button);
if(conf.bars.selbar && ev->window == infobar[sc].selbar->win)
barwin_refresh(infobar[sc].selbar);
for(i = 1; i < conf.ntag[sc] + 1; ++i)
if(ev->window == infobar[sc].tags[i]->win)
barwin_refresh(infobar[sc].tags[i]);
@@ -421,6 +447,8 @@ keypress(XKeyPressedEvent *ev)
void
mappingnotify(XMappingEvent *ev)
{
XRefreshKeyboardMapping(ev);
if(ev->request == MappingKeyboard)
grabkeys();
@@ -453,6 +481,7 @@ propertynotify(XPropertyEvent *ev)
{
Client *c;
Window trans;
XWMHints *h;
if(ev->state == PropertyDelete)
return;
@@ -461,7 +490,6 @@ propertynotify(XPropertyEvent *ev)
{
switch(ev->atom)
{
default: break;
case XA_WM_TRANSIENT_FOR:
XGetTransientForHint(dpy, c->win, &trans);
if((c->flags & TileFlag || c->flags & MaxFlag))
@@ -472,12 +500,25 @@ propertynotify(XPropertyEvent *ev)
case XA_WM_NORMAL_HINTS:
client_size_hints(c);
break;
case XA_WM_HINTS:
if((h = XGetWMHints(dpy, c->win)) && (h->flags & XUrgencyHint) && c != sel)
{
c->flags |= UrgentFlag;
tags[c->screen][c->tag].urgent = True;
infobar_draw_taglist(c->screen);
XFree(h);
}
break;
case XA_WM_NAME:
client_get_name(c);
break;
default:
if(ev->atom == net_atom[net_wm_name])
client_get_name(c);
break;
}
if(ev->atom == net_atom[net_wm_name])
client_get_name(c);
}
return;

View File

@@ -42,12 +42,13 @@
void
ewmh_init_hints(void)
{
int i = 1, j, showing_desk = 0;
int i = 1, s, j, showing_desk = 0;
char root_name[] = WMFS_VERSION;
char class[] = "wmfs", st[64];
long pid = (long)getpid();
net_atom = emalloc(net_last + screen_count(), sizeof(Atom));
s = screen_count();
net_atom = emalloc(net_last + s, sizeof(Atom));
/* EWMH hints */
net_atom[net_supported] = ATOM("_NET_SUPPORTED");
@@ -93,14 +94,14 @@ ewmh_init_hints(void)
net_atom[wmfs_cmd] = ATOM("_WMFS_CMD");
/* Multi atom _WMFS_STATUSTEXT_<screennum> */
for(j = 0; j < screen_count(); ++j)
for(j = 0; j < s; ++j)
{
sprintf(st, "_WMFS_STATUSTEXT_%d", j);
net_atom[wmfs_statustext + j] = ATOM(st);
}
XChangeProperty(dpy, ROOT, net_atom[net_supported], XA_ATOM, 32,
PropModeReplace, (uchar*)net_atom, net_last + screen_count());
PropModeReplace, (uchar*)net_atom, net_last + s);
XChangeProperty(dpy, ROOT, net_atom[wmfs_running], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&i, 1);
@@ -148,13 +149,11 @@ void
ewmh_update_current_tag_prop(void)
{
int t;
char *s = NULL;
char s[8] = { 0 };
screen_get_sel();
t = seltag[selscreen] - 1;
s = emalloc(8, sizeof(char));
/* Get current desktop (tag) */
XChangeProperty(dpy, ROOT, net_atom[net_current_desktop], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&t, 1);
@@ -179,8 +178,6 @@ ewmh_update_current_tag_prop(void)
PropModeReplace, (uchar*)tags[selscreen][seltag[selscreen]].layout.symbol,
strlen(tags[selscreen][seltag[selscreen]].layout.symbol));
free(s);
return;
}
@@ -202,7 +199,7 @@ ewmh_get_client_list(void)
XChangeProperty(dpy, ROOT, net_atom[net_client_list], XA_WINDOW, 32,
PropModeReplace, (uchar *)list, win_n);
free(list);
XFree(list);
return;
}
@@ -213,15 +210,17 @@ void
ewmh_get_desktop_names(void)
{
char *str = NULL;
int s, i, len = 0, pos = 0;
int S, s, i = 0, len = 0, pos = 0;
for(s = 0 ; s < screen_count(); ++s)
S = screen_count();
for(s = 0 ; s < S; ++s)
for(i = 1; i < conf.ntag[s] + 1; ++i)
len += strlen(tags[s][i].name);
str = emalloc(len + i + 1, sizeof(char*));
for(s = 0; s < screen_count(); ++s)
for(s = 0; s < S; ++s)
for(i = 1; i < conf.ntag[s] + 1; ++i, ++pos)
{
strncpy(str + pos, tags[s][i].name, strlen(tags[s][i].name));
@@ -264,14 +263,16 @@ void
ewmh_set_workarea(void)
{
long *data;
int i, j, tag_c = 0, pos = 0;
int i, s, j, tag_c = 0, pos = 0;
for(i = 0; i < screen_count(); ++i)
s = screen_count();
for(i = 0; i < s; ++i)
tag_c += conf.ntag[i];
data = emalloc(tag_c * 4, sizeof(long));
for(i = 0; i < screen_count(); ++i)
for(i = 0; i < s; ++i)
for(j = 0; j < conf.ntag[i]; ++j)
{
data[pos++] = spgeo[i].x;
@@ -299,7 +300,6 @@ ewmh_manage_net_wm_state(long data_l[], Client *c)
if(data_l[0] == _NET_WM_STATE_ADD && !(c->flags & FSSFlag))
{
c->screen = screen_get_with_geo(c->geo.x, c->geo.y);
client_unmap(c);
c->flags &= ~UnmapFlag;
XMapWindow(dpy, c->win);
XReparentWindow(dpy, c->win, ROOT, spgeo[c->screen].x, spgeo[c->screen].y);
@@ -316,6 +316,7 @@ ewmh_manage_net_wm_state(long data_l[], Client *c)
client_raise(c);
client_focus(c);
XUnmapWindow(dpy, c->frame);
}
else if(data_l[0] == _NET_WM_STATE_REMOVE && (c->flags & FSSFlag))
{

View File

@@ -220,16 +220,26 @@ frame_update(Client *c)
{
XSetWindowBackground(dpy, c->button[i], c->colors.frame);
XClearWindow(dpy, c->button[i]);
XSetWindowBorder(dpy, c->button[i], getcolor(c->colors.fg));
/* Button's lines */
if(conf.titlebar.button[i].nlines)
if((!conf.titlebar.button[i].flags)
|| ((conf.titlebar.button[i].flags & FreeFlag) && (c->flags & FreeFlag))
|| ((conf.titlebar.button[i].flags & MaxFlag) && (c->flags & MaxFlag))
|| ((conf.titlebar.button[i].flags & TileFlag) && (c->flags & TileFlag)))
{
XSetForeground(dpy, gc, getcolor(c->colors.fg));
XDrawSegments(dpy, c->button[i], gc,
conf.titlebar.button[i].linecoord,
conf.titlebar.button[i].nlines);
XSetWindowBorder(dpy, c->button[i], getcolor(c->colors.fg));
/* Button's lines */
if(conf.titlebar.button[i].nlines)
{
XSetForeground(dpy, gc, getcolor(c->colors.fg));
XDrawSegments(dpy, c->button[i], gc,
conf.titlebar.button[i].linecoord,
conf.titlebar.button[i].nlines);
}
}
else
XSetWindowBorder(dpy, c->button[i], c->colors.frame);
}
}

View File

@@ -37,12 +37,14 @@
void
infobar_init(void)
{
int sc, i, j;
int s, sc, i, j = 0;
s = screen_count();
if(!infobar)
infobar = emalloc(screen_count(), sizeof(InfoBar));
infobar = emalloc(s, sizeof(InfoBar));
for(sc = 0; sc < screen_count(); ++sc)
for(sc = 0; sc < s; ++sc)
{
j = 0;
infobar[sc].geo.height = INFOBARH;
@@ -70,35 +72,63 @@ infobar_init(void)
sgeo[sc].width, infobar[sc].geo.height,
conf.colors.bar, conf.colors.text, False, False, conf.border.bar);
infobar[sc].tags_board = barwin_create(infobar[sc].bar->win,
((conf.layout_placement) ? textw(tags[sc][seltag[sc]].layout.symbol) + PAD * 1.5: 0), 0,
textw(tags[sc][0].name) + PAD, /* Base size, will change */
infobar[sc].geo.height,
conf.colors.bar, conf.colors.text, False, False, False);
/* Create tags window */
for(i = 1; i < conf.ntag[sc] + 1; ++i)
{
infobar[sc].tags[i] = barwin_create(infobar[sc].bar->win, j, 0,
infobar[sc].tags[i] = barwin_create(infobar[sc].tags_board->win, j, 0,
textw(tags[sc][i].name) + PAD,
infobar[sc].geo.height,
conf.colors.bar, conf.colors.text, False, False, conf.border.tag);
j += textw(tags[sc][i].name) + PAD;
barwin_resize(infobar[sc].tags_board, j, infobar[sc].geo.height);
barwin_map_subwin(infobar[sc].tags[i]);
}
/* Create layout switch barwindow */
infobar[sc].layout_button = barwin_create(infobar[sc].bar->win, j + PAD / 2, 0,
textw(tags[sc][seltag[sc]].layout.symbol) + PAD,
infobar[sc].geo.height,
conf.colors.layout_bg, conf.colors.layout_fg,
False, False, conf.border.layout);
infobar[sc].layout_button = barwin_create(infobar[sc].bar->win,
((conf.layout_placement) ? 0 : (j + PAD / 2)), 0,
textw(tags[sc][seltag[sc]].layout.symbol) + PAD,
infobar[sc].geo.height,
conf.colors.layout_bg, conf.colors.layout_fg,
False, False, conf.border.layout);
/* Selbar */
if(conf.bars.selbar)
infobar[sc].selbar = barwin_create(infobar[sc].bar->win,
((conf.layout_placement)
? (j + PAD / 2)
: infobar[sc].layout_button->geo.x + infobar[sc].layout_button->geo.width + PAD / 2), 1,
(sel) ? textw(sel->title) + PAD : 1,
infobar[sc].geo.height - 2,
conf.selbar.bg, conf.selbar.fg, False, False, False);
/* Map/Refresh all */
barwin_map(infobar[sc].bar);
barwin_map_subwin(infobar[sc].bar);
barwin_map(infobar[sc].tags_board);
barwin_map_subwin(infobar[sc].tags_board);
if(conf.border.layout)
barwin_map_subwin(infobar[sc].layout_button);
if(conf.bars.selbar)
barwin_map(infobar[sc].selbar);
barwin_refresh_color(infobar[sc].bar);
barwin_refresh(infobar[sc].bar);
/* Default statustext is set here */
for(i = 0; i < screen_count(); ++i)
infobar[i].statustext = _strdup(WMFS_VERSION);
infobar[sc].statustext = _strdup(WMFS_VERSION);
infobar_draw(sc);
}
@@ -113,8 +143,9 @@ infobar_draw(int sc)
{
infobar_draw_taglist(sc);
infobar_draw_layout(sc);
infobar_draw_selbar(sc);
barwin_refresh_color(infobar[sc].bar);
infobar_draw_statustext(sc, infobar[sc].statustext);
statustext_handle(sc, infobar[sc].statustext);
return;
}
@@ -125,38 +156,121 @@ infobar_draw(int sc)
void
infobar_draw_layout(int sc)
{
if(!conf.layout_placement)
barwin_move(infobar[sc].layout_button, infobar[sc].tags_board->geo.width + PAD / 2, 0);
barwin_resize(infobar[sc].layout_button, textw(tags[sc][seltag[sc]].layout.symbol) + PAD, infobar[sc].geo.height);
barwin_refresh_color(infobar[sc].layout_button);
if(tags[sc][seltag[sc]].layout.symbol)
barwin_draw_text(infobar[sc].layout_button, PAD / 2, FHINFOBAR, tags[sc][seltag[sc]].layout.symbol);
return;
}
/** Draw Selbar (selected client title bar in infobar
*\param sc Screen Number
*/
void
infobar_draw_selbar(int sc)
{
char *str = NULL;
if(!conf.bars.selbar)
return;
if(!sel)
{
barwin_unmap(infobar[sc].selbar);
return;
}
else if(sel && !infobar[sc].selbar->mapped)
barwin_map(infobar[sc].selbar);
if(conf.selbar.maxlenght >= 0 && sel)
{
str = emalloc(conf.selbar.maxlenght + 4, sizeof(char));
strncpy(str, sel->title, conf.selbar.maxlenght);
if(strlen(sel->title) > conf.selbar.maxlenght)
strcat(str, "...");
}
barwin_resize(infobar[sc].selbar, textw(str ? str : sel->title) + PAD, infobar[sc].geo.height - 2);
barwin_move(infobar[sc].selbar,
((conf.layout_placement)
? (infobar[sc].tags_board->geo.x + infobar[sc].tags_board->geo.width + PAD / 2)
: (infobar[sc].layout_button->geo.x + infobar[sc].layout_button->geo.width + PAD / 2)), 1);
barwin_refresh_color(infobar[sc].selbar);
barwin_draw_text(infobar[sc].selbar, PAD / 2, FHINFOBAR - 1, ((str) ? str : sel->title));
barwin_refresh(infobar[sc].selbar);
IFREE(str);
return;
}
/** Draw the taglist in the InfoBar
*\param sc Screen number
*/
void
infobar_draw_taglist(int sc)
{
int i;
int i, x, j;
Client *c;
Bool is_occupied[MAXTAG];
for(i = 1; i < conf.ntag[sc] + 1; ++i)
if(conf.layout_placement)
barwin_move(infobar[sc].tags_board, textw(tags[sc][seltag[sc]].layout.symbol) + PAD * 1.5, 0);
for(i = 0; i < MAXTAG; i++)
is_occupied[i] = False;
for(c = clients; c; c = c->next)
if(c->screen == sc)
is_occupied[c->tag] = True;
for(i = 1, x = j = 0; i < conf.ntag[sc] + 1; ++i)
{
infobar[sc].tags[i]->bg = ((i == seltag[sc]) ? conf.colors.tagselbg : conf.colors.bar);
infobar[sc].tags[i]->fg = ((i == seltag[sc]) ? conf.colors.tagselfg : conf.colors.text);
/* Autohide tag feature */
if(conf.tagautohide)
{
if(!is_occupied[i] && i != seltag[sc])
{
barwin_unmap(infobar[sc].tags[i]);
continue;
}
if(!infobar[sc].tags[i]->mapped)
barwin_map(infobar[sc].tags[i]);
barwin_move(infobar[sc].tags[i], x, 0);
x += infobar[sc].tags[i]->geo.width;
barwin_resize(infobar[sc].tags_board, x, infobar[sc].geo.height);
}
infobar[sc].tags[i]->bg = tags[sc][i].urgent
? conf.colors.tagurbg
: ((i == seltag[sc] || tags[sc][seltag[sc]].tagad & TagFlag(i))
? conf.colors.tagselbg
: (is_occupied[i]
? conf.colors.tag_occupied_bg
: conf.colors.bar));
infobar[sc].tags[i]->fg = tags[sc][i].urgent
? conf.colors.tagurfg
: ((i == seltag[sc] || tags[sc][seltag[sc]].tagad & TagFlag(i))
? conf.colors.tagselfg
: conf.colors.text);
barwin_refresh_color(infobar[sc].tags[i]);
/* Colorize a tag if there are clients in this */
for(c = clients; c; c = c->next)
{
if(c->screen == sc)
{
infobar[sc].tags[c->tag]->bg = ((c->tag == seltag[sc]) ? conf.colors.tagselbg : conf.colors.tag_occupied_bg);
barwin_refresh_color(infobar[sc].tags[i]);
}
}
if(tags[sc][i].name)
barwin_draw_text(infobar[sc].tags[i], PAD / 2, FHINFOBAR, tags[sc][i].name);
}
@@ -164,86 +278,46 @@ infobar_draw_taglist(int sc)
return;
}
/** Draw text in the statustext and parse color format
*\param sc Screen
*\param str String
/** Update taglist geo
*\param sc Screen number
*/
void
infobar_draw_statustext(int sc, char *str)
infobar_update_taglist(int sc)
{
char *buf = NULL;
char *strwc = NULL;
char col[8] = { 0 };
int i, j, c, k = 0;
char *lastst;
int i, j;
/* If the str == the current statustext, return (not needed) */
if(!str)
return;
barwin_refresh_color(infobar[sc].bar);
/* save last status text address (for free at the end) */
lastst = infobar[sc].statustext;
infobar[sc].statustext = _strdup(str);
strwc = _strdup(str);
/* Count how many color block there is and make a string without color block (\#....\)*/
for(i = j = c = 0; i < strlen(str); ++i, ++j)
for(i = 1, j = 0; i < conf.ntag[sc] + 1; ++i)
{
if(str[i] == '\\' && str[i + 1] == '#' && str[i + 8] == '\\')
/* If the tag i does not exist yet (graphically) or need full update */
if(!infobar[sc].tags[i] || infobar[sc].need_update)
{
++c;
i += 8;
--j;
infobar[sc].tags[i] = barwin_create(infobar[sc].tags_board->win, j, 0,
textw(tags[sc][i].name) + PAD,
infobar[sc].geo.height,
conf.colors.bar, conf.colors.text, False, False, conf.border.tag);
barwin_map(infobar[sc].tags[i]);
barwin_map_subwin(infobar[sc].tags[i]);
j += textw(tags[sc][i].name) + PAD;
barwin_resize(infobar[sc].tags_board, j, infobar[sc].geo.height);
continue;
}
else
strwc[j] = str[i];
barwin_move(infobar[sc].tags[i], j, 0);
j += textw(tags[sc][i].name) + PAD;
barwin_resize(infobar[sc].tags[i], textw(tags[sc][i].name) + PAD, infobar[sc].geo.height);
barwin_resize(infobar[sc].tags_board, j, infobar[sc].geo.height);
}
strwc[j] = '\0';
/* Draw a first time the statustext for non colorized text */
draw_text(infobar[sc].bar->dr, (sgeo[sc].width - SHADH) - textw(strwc),
FHINFOBAR, infobar[sc].bar->fg, 0, strwc);
/* Draw text with its color */
if(c)
{
buf = _strdup(strwc);
for(i = k; i < strlen(str); ++i, ++k)
if(str[i] == '\\' && str[i + 1] == '#' && str[i + 8] == '\\')
{
/* Store current color in col[] */
for(j = 0, ++i; str[i] != '\\'; col[j++] = str[i++]);
buf += k;
/* Draw a rectangle with the bar color to draw the text properly */
draw_rectangle(infobar[sc].bar->dr, (sgeo[sc].width - SHADH) - textw(buf),
0, INFOBARH - (sgeo[sc].width - SHADH) - textw(buf),
INFOBARH, conf.colors.bar);
/* Draw text with its color */
draw_text(infobar[sc].bar->dr, (sgeo[sc].width - SHADH) - textw(buf),
FHINFOBAR, col, 0, buf);
buf = _strdup(strwc);
++i;
}
free(buf);
}
barwin_refresh(infobar[sc].bar);
free(lastst);
free(strwc);
infobar[sc].need_update = False;
return;
}
/** Destroy the InfoBar
*/
void
@@ -255,11 +329,16 @@ infobar_destroy(void)
{
barwin_delete(infobar[sc].layout_button);
barwin_delete_subwin(infobar[sc].layout_button);
for(i = 1; i < conf.ntag[sc] + 1; ++i)
{
barwin_delete_subwin(infobar[sc].tags[i]);
barwin_delete(infobar[sc].tags[i]);
}
barwin_delete_subwin(infobar[sc].tags_board);
barwin_delete(infobar[sc].tags_board);
barwin_delete(infobar[sc].selbar);
barwin_delete_subwin(infobar[sc].bar);
barwin_delete(infobar[sc].bar);
}
@@ -320,3 +399,33 @@ uicb_infobar_togglepos(uicb_t cmd)
return;
}
/** Toggle the tag_autohide mode
* \param cmd uicb_t type unused
*/
void
uicb_toggle_tagautohide(uicb_t cmd)
{
int i, x;
screen_get_sel();
conf.tagautohide = !conf.tagautohide;
if(!conf.tagautohide)
{
for(i = 1, x = 0; i < conf.ntag[selscreen] + 1; ++i)
{
if(!infobar[selscreen].tags[i]->mapped)
barwin_map(infobar[selscreen].tags[i]);
barwin_move(infobar[selscreen].tags[i], x, 0);
x += infobar[selscreen].tags[i]->geo.width;
}
barwin_resize(infobar[selscreen].tags_board, x, infobar[selscreen].geo.height);
}
infobar_draw(selscreen);
return;
}

View File

@@ -32,6 +32,28 @@
#include "wmfs.h"
const func_name_list_t layout_list[] =
{
{"tile", tile },
{"tile_right", tile },
{"tile_left", tile_left },
{"tile_top", tile_top },
{"tile_bottom", tile_bottom },
{"tile_grid", grid },
{"grid", grid },
{"mirror_vertical", mirror_vertical },
{"tile_mirror_vertical", mirror_vertical },
{"mirror_horizontal", mirror_horizontal },
{"tile_mirror_horizontal", mirror_horizontal },
{"layer", layer },
{"max", maxlayout },
{"maxlayout", maxlayout },
{"freelayout", freelayout },
{"free", freelayout },
{ NULL, NULL }
};
/** Init WMFS
*/
void
@@ -39,7 +61,6 @@ init(void)
{
/* First init */
ewmh_init_hints();
init_layout();
init_conf();
init_gc();
init_font();
@@ -154,75 +175,39 @@ init_root(void)
return;
}
/** Init layout
*/
void
init_layout(void)
{
int i;
const func_name_list_t layout_list_tmp[] =
{
{"tile", tile },
{"tile_right", tile },
{"tile_left", tile_left },
{"tile_top", tile_top },
{"tile_bottom", tile_bottom },
{"tile_grid", grid },
{"grid", grid },
{"mirror_vertical", mirror_vertical },
{"tile_mirror_vertical", mirror_vertical },
{"mirror_horizontal", mirror_horizontal },
{"tile_mirror_horizontal", mirror_horizontal },
{"layer", layer },
{"max", maxlayout },
{"maxlayout", maxlayout },
{"freelayout", freelayout },
{"free", freelayout }
};
layout_list = emalloc(LEN(layout_list_tmp), sizeof(func_name_list_t));
memset(layout_list, 0, LEN(layout_list_tmp));
for(i = 0; i < LEN(layout_list_tmp); ++i)
layout_list[i] = layout_list_tmp[i];
return;
}
/** Init statustext shell script
*/
void
init_status(void)
{
int fd;
struct stat st;
char *home;
status_path = emalloc(strlen(getenv("HOME")) + strlen(DEF_STATUS) + 2, sizeof(char));
conf.status_pid = -1;
estatus = False;
sprintf(status_path, "%s/"DEF_STATUS, getenv("HOME"));
if(!(fd = open(status_path, O_RDONLY))
|| !fopen(status_path, "r"))
if(!conf.status_path)
{
free(status_path);
estatus = False;
if(!(home = getenv("HOME")))
{
warnx("HOME not set, can't launch status.sh");
return;
}
conf.status_path = emalloc(strlen(home) + strlen(DEF_STATUS) + 2, sizeof(char));
sprintf(conf.status_path, "%s/"DEF_STATUS, home);
}
if (stat(conf.status_path, &st) == -1)
{
warn("%s", conf.status_path);
return;
}
stat(status_path, &st);
if(st.st_size && st.st_mode & S_IXUSR)
{
estatus = True;
system(status_path);
}
else
warnx("status.sh file present in wmfs directory can't be executed, try 'chmod +x %s'.",
status_path);
close(fd);
warnx("status file specified in configuratin (status_path) or present in wmfs directory can't be executed, try 'chmod +x %s'.", conf.status_path);
return;
}

View File

@@ -42,7 +42,7 @@ static char *complete_on_command(char*, size_t);
static char *complete_on_files(char*, size_t);
void
launcher_execute(Launcher launcher)
launcher_execute(Launcher *launcher)
{
BarWindow *bw;
Bool found;
@@ -52,7 +52,7 @@ launcher_execute(Launcher launcher)
char buf[512] = { 0 };
char tmpbuf[512] = { 0 };
char *complete;
int pos = 0, x;
int i, pos = 0, histpos = 0, x;
int tabhits = 0;
KeySym ks;
XEvent ev;
@@ -76,12 +76,16 @@ launcher_execute(Launcher launcher)
/* First draw of the cursor */
XSetForeground(dpy, gc, getcolor(infobar[selscreen].bar->fg));
XDrawLine(dpy, bw->dr, gc, textw(launcher.prompt) + textw(" "),
2, textw(launcher.prompt) + textw(" "), INFOBARH - 4);
/*XDrawLine(dpy, bw->dr, gc, 1 + textw(launcher->prompt) + textw(" "),
, 1 + textw(launcher->prompt) + textw(" "), INFOBARH - 4);
*/
XDrawLine(dpy, bw->dr, gc,
1 + textw(launcher->prompt) + textw(" ") + textw(buf), 2,
1 + textw(launcher->prompt) + textw(" ") + textw(buf), INFOBARH - 4);
barwin_refresh(bw);
barwin_draw_text(bw, 1, FHINFOBAR - 1, launcher.prompt);
barwin_draw_text(bw, 1, FHINFOBAR - 1, launcher->prompt);
while(my_guitar_gently_wheeps)
{
@@ -91,8 +95,14 @@ launcher_execute(Launcher launcher)
/* Check Ctrl-c / Ctrl-d */
if(ev.xkey.state & ControlMask)
{
if(ks == XK_c || ks == XK_d)
ks = XK_Escape;
else if(ks == XK_p)
ks = XK_Up;
else if(ks == XK_n)
ks = XK_Down;
}
/* Check if there is a keypad */
if(IsKeypadKey(ks) && ks == XK_KP_Enter)
@@ -100,13 +110,43 @@ launcher_execute(Launcher launcher)
switch(ks)
{
case XK_Up:
if(launcher->nhisto)
{
if(histpos >= launcher->nhisto)
histpos = 0;
strncpy(buf, launcher->histo[launcher->nhisto - ++histpos], sizeof(buf));
pos = strlen(buf);
}
break;
case XK_Down:
if(launcher->nhisto && histpos > 0 && histpos < launcher->nhisto)
{
strncpy(buf, launcher->histo[launcher->nhisto - --histpos], sizeof(buf));
pos = strlen(buf);
}
break;
case XK_Return:
spawn("%s %s", launcher.command, buf);
spawn("%s %s", launcher->command, buf);
/* Histo */
if(launcher->nhisto + 1 > HISTOLEN)
{
for(i = launcher->nhisto - 1; i > 1; --i)
strncpy(launcher->histo[i], launcher->histo[i - 1], sizeof(launcher->histo[i]));
launcher->nhisto = 0;
}
/* Store in histo array */
strncpy(launcher->histo[launcher->nhisto++], buf, sizeof(buf));
my_guitar_gently_wheeps = 0;
break;
case XK_Escape:
my_guitar_gently_wheeps = 0;
break;
case XK_Tab:
/*
* completion
@@ -156,9 +196,10 @@ launcher_execute(Launcher launcher)
if(pos)
buf[--pos] = 0;
break;
default:
lastwastab = False;
strncat(buf, tmp, sizeof(buf));
strncat(buf, tmp, sizeof(tmp));
++pos;
break;
}
@@ -168,11 +209,11 @@ launcher_execute(Launcher launcher)
/* Update cursor position */
XSetForeground(dpy, gc, getcolor(infobar[selscreen].bar->fg));
XDrawLine(dpy, bw->dr, gc,
1 + textw(launcher.prompt) + textw(" ") + textw(buf), 2,
1 + textw(launcher.prompt) + textw(" ") + textw(buf), INFOBARH - 4);
1 + textw(launcher->prompt) + textw(" ") + textw(buf), 2,
1 + textw(launcher->prompt) + textw(" ") + textw(buf), INFOBARH - 4);
barwin_draw_text(bw, 1, FHINFOBAR - 1, launcher.prompt);
barwin_draw_text(bw, 1 + textw(launcher.prompt) + textw(" "), FHINFOBAR - 1, buf);
barwin_draw_text(bw, 1, FHINFOBAR - 1, launcher->prompt);
barwin_draw_text(bw, 1 + textw(launcher->prompt) + textw(" "), FHINFOBAR - 1, buf);
barwin_refresh(bw);
}
else
@@ -197,7 +238,7 @@ uicb_launcher(uicb_t cmd)
for(i = 0; i < conf.nlauncher; ++i)
if(!strcmp(cmd, conf.launcher[i].name))
launcher_execute(conf.launcher[i]);
launcher_execute(&conf.launcher[i]);
return;
}

View File

@@ -71,7 +71,7 @@ freelayout(int screen)
&& c->screen == screen_get_sel()
&& !(c->flags & MaxFlag))
{
client_moveresize(c, c->ogeo, True);
client_moveresize(c, c->free_geo, True);
c->flags &= ~(TileFlag | LMaxFlag);
}
@@ -93,7 +93,10 @@ layoutswitch(Bool b)
if(tags[selscreen][seltag[selscreen]].layout.func == freelayout)
for(c = clients; c && (c->tag != seltag[selscreen] && c->screen != selscreen); c = c->next)
{
c->ogeo = c->geo;
c->free_geo = c->geo;
}
for(i = 0; i < conf.nlayout; ++i)
{
@@ -328,7 +331,7 @@ multi_tile(int screen, Position type)
XRectangle sg = sgeo[screen];
XRectangle mastergeo = {sg.x, sg.y, 0, 0};
XRectangle cgeo = {sg.x, sg.y, 0, 0};
uint i, n, tilesize, mwfact, nmaster = tags[screen][seltag[screen]].nmaster;
uint i, n, tilesize = 0, mwfact, nmaster = tags[screen][seltag[screen]].nmaster;
for(n = 0, c = tiled_client(screen, clients); c; c = tiled_client(screen, c->next), ++n);
CHECK(n);
@@ -459,7 +462,7 @@ mirror(int screen, Bool horizontal)
XRectangle mastergeo = {sg.x, sg.y, sg.width, sg.height};
XRectangle cgeo = {sg.x, sg.y , sg.width, sg.height};
XRectangle nextg[2] = { {0} };
uint i, n, tilesize, mwfact;
uint i, n, tilesize = 0, mwfact;
uint nmaster = tags[screen][seltag[screen]].nmaster;
int pa, imp;
Bool isp = 0;
@@ -775,11 +778,14 @@ uicb_togglefree(uicb_t cmd)
if((sel->flags & FreeFlag))
{
sel->flags &= ~(TileFlag | MaxFlag | LMaxFlag);
client_moveresize(sel, sel->ogeo, True);
client_moveresize(sel, sel->free_geo, True);
client_raise(sel);
}
else
{
sel->free_geo = sel->geo;
sel->ogeo = sel->geo;
}
client_update_attributes(sel);
@@ -802,6 +808,7 @@ uicb_togglemax(uicb_t cmd)
if(!(sel->flags & MaxFlag))
{
sel->ogeo = sel->geo;
sel->free_geo = sel->geo;
sel->flags &= ~(TileFlag | FreeFlag);
client_maximize(sel);
client_raise(sel);
@@ -809,6 +816,8 @@ uicb_togglemax(uicb_t cmd)
}
else
{
sel->geo = sel->free_geo;
client_moveresize(sel, sel->geo, True);
sel->flags &= ~MaxFlag;
tags[selscreen][seltag[selscreen]].layout.func(selscreen);
}
@@ -907,3 +916,48 @@ layout_set_client_master(Client *c)
return;
}
/** Check the selected client is max
* \param cmd uicb_t type unused
*/
Bool
uicb_checkmax(uicb_t cmd)
{
if(!sel)
return False;
if(sel->flags & MaxFlag)
return True;
return False;
}
/** Check the selected client is free
* \param cmd uicb_t type unused
*/
Bool
uicb_checkfree(uicb_t cmd)
{
if(!sel)
return False;
if(sel->flags & FreeFlag)
return True;
return False;
}
/** Check layout type
* \param cmd uicb_t type layout type
*/
Bool
uicb_checklayout(uicb_t cmd)
{
screen_get_sel();
if(!strcmp(cmd, tags[selscreen][seltag[selscreen]].layout.type))
return True;
return False;
}

View File

@@ -35,7 +35,6 @@
void
menu_init(Menu *menu, char *name, int nitem, uint bg_f, char *fg_f, uint bg_n, char *fg_n)
{
/* Item */
menu->nitem = nitem;
menu->item = emalloc(sizeof(MenuItem), nitem);
@@ -63,15 +62,23 @@ menu_new_item(MenuItem *mi, char *name, void *func, char *cmd)
void
menu_draw(Menu menu, int x, int y)
{
int i, width;
int i, width, height, out;
XEvent ev;
BarWindow *item[menu.nitem];
BarWindow *frame;
width = menu_get_longer_string(menu.item, menu.nitem);
width = menu_get_longer_string(menu.item, menu.nitem) + PAD * 3;
height = menu.nitem * (INFOBARH - SHADH);
/* Frame barwin */
frame = barwin_create(ROOT, x, y, width + SHADH, menu.nitem * (INFOBARH - SHADH) + SHADH * 2,
screen_get_sel();
if((out = x + width - MAXW) > 0)
x -= out;
if((out = y + height - MAXH) > 0)
y -= out;
frame = barwin_create(ROOT, x, y, width + SHADH, height + SHADH * 2,
menu.colors.normal.bg, menu.colors.normal.fg, False, False, True);
barwin_map(frame);
@@ -84,7 +91,7 @@ menu_draw(Menu menu, int x, int y)
SHADH,
(i * (INFOBARH - SHADH) + SHADH),
width - SHADH,
INFOBARH,
INFOBARH - SHADH,
menu.colors.normal.bg,
menu.colors.normal.fg,
True, False, False);
@@ -127,12 +134,7 @@ menu_manage_event(XEvent *ev, Menu *menu, BarWindow *winitem[])
{
if(ev->xbutton.window == winitem[i]->win
&& (ev->xbutton.button == Button1 || ev->xbutton.button == Button2))
{
if(menu->item[i].func)
menu->item[i].func(menu->item[i].cmd);
quit = True;
}
quit = menu_activate_item(menu, i);
else if(ev->xbutton.window != winitem[i]->win)
++c;
else if(ev->xbutton.button == Button4)
@@ -161,9 +163,7 @@ menu_manage_event(XEvent *ev, Menu *menu, BarWindow *winitem[])
break;
case XK_Return:
if(menu->item[menu->focus_item].func)
menu->item[menu->focus_item].func(menu->item[menu->focus_item].cmd);
quit = True;
quit = menu_activate_item(menu, menu->focus_item);
break;
case XK_Escape:
@@ -190,6 +190,33 @@ menu_manage_event(XEvent *ev, Menu *menu, BarWindow *winitem[])
return quit;
}
Bool
menu_activate_item(Menu *menu, int i)
{
int j, x, y;
if(menu->item[i].submenu)
{
for(j = 0; j < conf.nmenu; ++j)
if(!strcmp(menu->item[i].submenu, conf.menu[j].name))
{
y = menu->y + ((i - 1) * INFOBARH + PAD) - SHADH * 2;
x = menu->x + menu_get_longer_string(menu->item, menu->nitem) + PAD * 3;
menu_draw(conf.menu[j], x, y);
return True;
}
}
else if(menu->item[i].func)
{
menu->item[i].func(menu->item[i].cmd);
return True;
}
return False;
}
void
menu_focus_item(Menu *menu, int item, BarWindow *winitem[])
@@ -219,26 +246,44 @@ menu_focus_item(Menu *menu, int item, BarWindow *winitem[])
void
menu_draw_item_name(Menu *menu, int item, BarWindow *winitem[])
{
int x;
int width = menu_get_longer_string(menu->item, menu->nitem);
barwin_draw_text(winitem[item],
((width / 2) - (textw(menu->item[item].name) / 2)),
FHINFOBAR,
menu->item[item].name);
switch(menu->align)
{
case MA_Left:
x = PAD * 3 / 2;
break;
case MA_Right:
x = width - textw(menu->item[item].name) + PAD * 3 / 2;
break;
default:
case MA_Center:
x = width / 2 - textw(menu->item[item].name) / 2 + PAD * 3 / 2;
break;
}
barwin_draw_text(winitem[item], x, FHINFOBAR, menu->item[item].name);
if(menu->item[item].check)
if(menu->item[item].check(menu->item[item].cmd))
barwin_draw_text(winitem[item], PAD / 3, FHINFOBAR, "*");
if(menu->item[item].submenu)
barwin_draw_text(winitem[item], width + PAD * 2, FHINFOBAR, ">");
return;
}
int
menu_get_longer_string(MenuItem *mt, int nitem)
menu_get_longer_string(MenuItem *mi, int nitem)
{
int i, l = 0;
int i, w, l = 0;
for(i = 0; i < nitem; ++i)
if(textw(mt[i].name) > l)
l = textw(mt[i].name);
if((w = textw(mi[i].name)) > l)
l = w;
return l + PAD;
return l;
}
void
@@ -254,7 +299,11 @@ uicb_menu(uicb_t cmd)
if(!strcmp(cmd, conf.menu[i].name))
{
if(conf.menu[i].place_at_mouse)
{
XQueryPointer(dpy, ROOT, &w, &w, &x, &y, &d, &d, (uint *)&u);
conf.menu[i].x = x;
conf.menu[i].y = y;
}
else
{
screen_get_sel();
@@ -266,3 +315,13 @@ uicb_menu(uicb_t cmd)
return;
}
void
menu_clear(Menu *menu)
{
IFREE(menu->item);
menu->nitem = 0;
return;
}

View File

@@ -53,7 +53,6 @@ void
mouse_move_tile_client(Client **c)
{
Client *sc;
Window w;
int d;
@@ -88,7 +87,7 @@ mouse_move_tag_client(Client *c)
s = c->screen;
XQueryPointer(dpy, infobar[selscreen].bar->win, &w, &w, &d, &d, &d, &d, (uint*)&d);
XQueryPointer(dpy, infobar[selscreen].tags_board->win, &w, &w, &d, &d, &d, &d, (uint*)&d);
for(i = 1; i < conf.ntag[selscreen] + 1; ++i)
if(infobar[selscreen].tags[i]->win == w

605
src/parse/parse.c Normal file
View File

@@ -0,0 +1,605 @@
/*
* Copyright (c) 2010 Philippe Pepiot <phil@philpep.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <err.h>
#include "../wmfs.h"
#define TOKEN(t) \
do { \
kw->type = (t); \
TAILQ_INSERT_TAIL(&keywords, kw, entry); \
kw = malloc(sizeof(*kw)); \
} while (0)
#define NEW_WORD() \
do { \
if (j > 0) { \
e->name[j] = '\0'; \
e->line = file.line; \
TAILQ_INSERT_TAIL(&stack, e, entry); \
e = malloc(sizeof(*e)); \
j = 0; \
TOKEN(WORD); \
} \
} while (0)
enum conf_type { SEC_START, SEC_END, WORD, EQUAL, LIST_START, LIST_END, NONE };
struct conf_keyword {
enum conf_type type;
TAILQ_ENTRY(conf_keyword) entry;
};
struct conf_stack {
char name[BUFSIZ];
int line;
TAILQ_ENTRY(conf_stack) entry;
};
struct conf_state {
Bool quote;
Bool comment;
char quote_char;
};
static void get_keyword(const char *buf, size_t n);
static void pop_keyword(void);
static void pop_stack(void);
static struct conf_sec *get_section(void);
static struct conf_opt *get_option(void);
static struct opt_type string_to_opt(char *);
#ifdef DEBUG
static void print_kw_tree(void);
static char * get_kw_name(enum conf_type);
#endif
static TAILQ_HEAD(, conf_keyword) keywords;
static TAILQ_HEAD(, conf_stack) stack;
static TAILQ_HEAD(, conf_sec) config;
static struct conf_keyword *curk; /* current keyword */
static struct conf_stack *curw; /* current word */
static const struct opt_type opt_type_null = { 0, 0, False, NULL };
static struct {
const char *name;
int line;
} file = { NULL, 1 };
static void
get_keyword(const char *buf, size_t n)
{
struct conf_keyword *kw;
size_t j, i;
struct conf_state s = { False, False, '\0' };
struct conf_stack *e;
TAILQ_INIT(&stack);
TAILQ_INIT(&keywords);
kw = emalloc(1, sizeof(*kw));
e = emalloc(1, sizeof(*e));
for(i = 0, j = 0; i < n; i++)
{
if (buf[i] == '\n' && s.comment == True) {
file.line++;
s.comment = False;
continue;
}
if (buf[i] == '#' && s.quote == False) {
s.comment = True;
continue;
}
if (s.comment == True)
continue;
if (buf[i] == s.quote_char && s.quote == True) {
NEW_WORD();
s.quote = False;
continue;
}
if ((buf[i] == '"' || buf[i] == '\'') &&
s.quote == False)
{
s.quote_char = buf[i];
s.quote = True;
continue;
}
if (buf[i] == '[' && s.quote == False) {
NEW_WORD();
TOKEN((buf[i+1] == '/') ? SEC_END : SEC_START);
if (buf[i+1] == '/')
i++;
continue;
}
if (buf[i] == ']' && s.quote == False) {
NEW_WORD();
continue;
}
if (buf[i] == '{' && s.quote == False) {
NEW_WORD();
TOKEN(LIST_START);
continue;
}
if (buf[i] == '}' && s.quote == False) {
NEW_WORD();
TOKEN(LIST_END);
continue;
}
if (buf[i] == ',' && s.quote == False) {
NEW_WORD();
continue;
}
if (buf[i] == '=' && s.quote == False) {
NEW_WORD();
TOKEN(EQUAL);
continue;
}
if (strchr("\t\n ", buf[i]) && s.quote == False) {
NEW_WORD();
if (buf[i] == '\n')
file.line++;
continue;
}
e->name[j++] = buf[i];
}
}
#ifdef DEBUG
static void
print_kw_tree(void)
{
struct conf_keyword *k;
struct conf_stack *s;
s = TAILQ_FIRST(&stack);
TAILQ_FOREACH(k, &keywords, entry)
printf("%s ", get_kw_name(k->type));
printf("\n");
}
static char *
get_kw_name(enum conf_type type)
{
switch (type) {
case SEC_START:
return ("SEC_START");
break;
case SEC_END:
return ("SEC_END");
break;
case WORD:
return ("WORD");
break;
case LIST_START:
return ("LIST_START ");
break;
case LIST_END:
return ("LIST_END ");
break;
case EQUAL:
return ("EQUAL ");
break;
default:
return ("NONE ");
break;
}
}
#endif
int
get_conf(const char *name)
{
int fd;
struct stat st;
char *buf;
struct conf_sec *s;
if (!name)
return (-1);
if ((fd = open(name, O_RDONLY)) == -1 ||
stat(name, &st) == -1)
{
warn("%s", name);
return (-1);
}
buf = (char*)mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, SEEK_SET);
if (buf == (char*) MAP_FAILED)
return -1;
get_keyword(buf, st.st_size);
munmap(buf, st.st_size);
close(fd);
warnx("%s read", name);
file.name = name;
curk = TAILQ_FIRST(&keywords);
curw = TAILQ_FIRST(&stack);
TAILQ_INIT(&config);
while (!TAILQ_EMPTY(&keywords)) {
switch (curk->type) {
case SEC_START:
s = get_section();
TAILQ_INSERT_TAIL(&config, s, entry);
break;
default:
errx(1, "%s:%d: near '%s', config out of any section",
file.name, curw->line, curw->name);
break;
}
}
return 0;
}
static struct conf_sec *
get_section(void)
{
struct conf_sec *s;
struct conf_opt *o;
struct conf_sec *sub;
s = emalloc(1, sizeof(*s));
s->name = strdup(curw->name);
TAILQ_INIT(&s->sub);
SLIST_INIT(&s->optlist);
pop_stack();
pop_keyword();
if (curk->type != WORD)
errx(1, "%s:%d: near '%s', missing section name",
file.name, curw->line, curw->name);
pop_keyword();
while (curk->type != SEC_END) {
switch (curk->type) {
case WORD:
o = get_option();
SLIST_INSERT_HEAD(&s->optlist, o, entry);
s->nopt++;
break;
case SEC_START:
sub = get_section();
TAILQ_INSERT_TAIL(&s->sub, sub, entry);
s->nsub++;
case SEC_END:
break;
default:
errx(1, "%s:%d: near '%s', syntax error",
file.name, curw->line, curw->name);
break;
}
}
pop_keyword();
if (curk->type != WORD)
errx(1, "%s:%d: near '%s', missing end-section name",
file.name, curw->line, curw->name);
if (strcmp(curw->name, s->name))
errx(1, "%s:%d: near '%s', non-closed section '%s'",
file.name, curw->line, curw->name, s->name);
pop_stack();
pop_keyword();
return s;
}
static struct conf_opt *
get_option(void)
{
struct conf_opt *o;
size_t j = 0;
o = emalloc(1, sizeof(*o));
o->name = strdup(curw->name);
o->used = False;
o->line = curw->line;
pop_stack();
pop_keyword();
if (curk->type != EQUAL)
errx(1, "%s:%d: near '%s', missing '=' here",
file.name, curw->line, curw->name);
pop_keyword();
switch (curk->type) {
case WORD:
o->val[0] = strdup(curw->name);
o->val[1] = NULL;
pop_stack();
break;
case LIST_START:
pop_keyword();
while (curk->type != LIST_END) {
if (curk->type != WORD)
errx(1, "%s:%d: near '%s', declaration into a list",
file.name, curw->line, curw->name);
o->val[j++] = strdup(curw->name);
pop_stack();
pop_keyword();
}
o->val[j] = NULL;
break;
default:
errx(1, "%s:%d: near '%s', syntax error",
file.name, curw->line, curw->name);
break;
}
pop_keyword();
return o;
}
static void
pop_keyword(void)
{
TAILQ_REMOVE(&keywords, curk, entry);
#ifdef DEBUG
warnx("%s", get_kw_name(curk->type));
#endif
free(curk);
curk = TAILQ_FIRST(&keywords);
}
static void
pop_stack(void)
{
TAILQ_REMOVE(&stack, curw, entry);
#ifdef DEBUG
warnx("%s", curw->name);
#endif
free(curw);
curw = TAILQ_FIRST(&stack);
}
void
print_unused(struct conf_sec *sec)
{
struct conf_sec *s;
struct conf_opt *o;
if (!sec)
{
TAILQ_FOREACH(s, &config, entry)
print_unused(s);
return;
}
SLIST_FOREACH(o, &sec->optlist, entry)
if (o->used == False)
warnx("%s:%d, unused param %s",
file.name, o->line, o->name);
TAILQ_FOREACH(s, &sec->sub, entry)
if (!TAILQ_EMPTY(&s->sub))
print_unused(s);
}
void
free_conf(struct conf_sec *sec)
{
struct conf_sec *s;
struct conf_opt *o;
size_t n;
if (!sec)
{
TAILQ_FOREACH(s, &config, entry)
{
free(s->name);
free_conf(s);
free(s);
}
return;
}
while (!SLIST_EMPTY(&sec->optlist))
{
o = SLIST_FIRST(&sec->optlist);
SLIST_REMOVE_HEAD(&sec->optlist, entry);
free(o->name);
for (n = 0; o->val[n]; n++)
free(o->val[n]);
free(o);
}
while (!TAILQ_EMPTY(&sec->sub))
{
s = TAILQ_FIRST(&sec->sub);
TAILQ_REMOVE(&sec->sub, s, entry);
free_conf(s);
}
}
struct conf_sec **
fetch_section(struct conf_sec *s, char *name)
{
struct conf_sec **ret;
struct conf_sec *sec;
size_t i = 0;
if (!name)
return NULL;
if (!s) {
ret = emalloc(2, sizeof(struct conf_sec *));
TAILQ_FOREACH(sec, &config, entry)
if (!strcmp(sec->name, name)) {
ret[0] = sec;
ret[1] = NULL;
break;
}
}
else {
ret = emalloc(s->nsub+1, sizeof(struct conf_sec *));
TAILQ_FOREACH(sec, &s->sub, entry) {
if (!strcmp(sec->name, name) && i < s->nsub)
ret[i++] = sec;
}
ret[i] = NULL;
}
return ret;
}
struct conf_sec *
fetch_section_first(struct conf_sec *s, char *name)
{
struct conf_sec *sec, *ret = NULL;
if (!name)
return NULL;
if (!s)
{
TAILQ_FOREACH(sec, &config, entry)
if (!strcmp(sec->name, name)) {
ret = sec;
break;
}
}
else
{
TAILQ_FOREACH(sec, &s->sub, entry)
if (!strcmp(sec->name, name)) {
ret = sec;
break;
}
}
return ret;
}
size_t
fetch_section_count(struct conf_sec **s)
{
size_t ret;
for (ret = 0; s[ret]; ret++);
return ret;
}
struct opt_type *
fetch_opt(struct conf_sec *s, char *dfl, char *name)
{
struct conf_opt *o;
struct opt_type *ret;
size_t i = 0;
if (!name)
return NULL;
ret = emalloc(10, sizeof(struct opt_type));
if (s) {
SLIST_FOREACH(o, &s->optlist, entry)
if (!strcmp(o->name, name)) {
while (o->val[i]) {
o->used = True;
ret[i] = string_to_opt(o->val[i]);
i++;
}
ret[i] = opt_type_null;
return ret;
}
}
ret[0] = string_to_opt(dfl);
ret[1] = opt_type_null;
return ret;
}
struct opt_type
fetch_opt_first(struct conf_sec *s, char *dfl, char *name)
{
struct conf_opt *o;
if (!name)
return opt_type_null;
else if (s)
SLIST_FOREACH(o, &s->optlist, entry)
if (!strcmp(o->name, name)) {
o->used = True;
return string_to_opt(o->val[0]);
}
return string_to_opt(dfl);
}
size_t
fetch_opt_count(struct opt_type *o)
{
size_t ret;
for(ret = 0; o[ret].str; ret++);
return ret;
}
static struct opt_type
string_to_opt(char *s)
{
struct opt_type ret = opt_type_null;
if (!s || !strlen(s))
return ret;
ret.num = strtol(s, (char**)NULL, 10);
ret.fnum = strtod(s, NULL);
if (!strcmp(s, "true") || !strcmp(s, "True") ||
!strcmp(s, "TRUE") || !strcmp(s, "1"))
ret.bool = True;
else
ret.bool = False;
ret.str = s;
return ret;
}

110
src/parse/parse.h Normal file
View File

@@ -0,0 +1,110 @@
/*
* Copyright (c) 2010 Philippe Pepiot <phil@philpep.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef PARSE_H
#define PARSE_H
#include <sys/queue.h>
struct conf_opt {
char *name;
char *val[10];
size_t nval;
Bool used;
int line;
SLIST_ENTRY(conf_opt) entry;
};
struct conf_sec {
char *name;
SLIST_HEAD(, conf_opt) optlist;
TAILQ_HEAD(, conf_sec) sub;
size_t nopt;
size_t nsub;
TAILQ_ENTRY(conf_sec) entry;
};
struct opt_type {
long int num;
float fnum;
Bool bool;
char *str;
};
/*
* Create config from file
* return -1 on failure
*/
int get_conf(const char *);
/*
* Print unused option name from section s (and subsections).
* If s == NULL print unused option name for all config struct.
*/
void print_unused(struct conf_sec *s);
/*
* Free the config struct.
* WARNING: This make all string
* returned by fetch_(opt|section)(_first) unusable.
*/
void free_conf(struct conf_sec *s);
/*
* Get all subsection matching the given name on the given
* section.
* If section == NULL, return subsections from root section.
* Return a NULL terminated array.
* Subsections are returned in order as they are in config file
* WARNING : This MUST be free() after use.
*/
struct conf_sec **fetch_section(struct conf_sec *, char *);
/*
* Get first subsection matching the given name
* on the given section. (first found on the file)
*/
struct conf_sec *fetch_section_first(struct conf_sec *, char *);
/*
* Count member of a conf_sec **
*/
size_t fetch_section_count(struct conf_sec **);
/*
* Return all options matching the given name on the given subsection.
* If none match or section == NULL return opt_type build with the
* given default param.
* WARNING: This MUST be free() after use.
* WARNING: The string member is directly taken from the config struct.
* WARNING: Returned in reverse order as they are in config file.
* (I think the last option MUST overwrite all others)
*/
struct opt_type fetch_opt_first(struct conf_sec *, char *, char *);
/*
* Get first (last in config file) option matching the given name
* on the given section.
* WARNING: The string member is directly taken from the config struct.
*/
struct opt_type *fetch_opt(struct conf_sec *, char *, char *);
/*
* Count member of a opt_type *
*/
size_t fetch_opt_count(struct opt_type *);
#endif /* PARSE_H */

View File

@@ -123,10 +123,13 @@ screen_set_sel(int screen)
if(screen < 0 || screen > screen_count() - 1)
screen = 0;
prevselscreen = selscreen;
client_focus(NULL);
XWarpPointer(dpy, None, ROOT, 0, 0, 0, 0,
sgeo[screen].x + sgeo[screen].width / 2,
sgeo[screen].y + sgeo[screen].height / 2);
selscreen = screen;
return;
@@ -138,6 +141,8 @@ screen_set_sel(int screen)
int
screen_get_sel(void)
{
int os = selscreen;
selscreen = 0;
#ifdef HAVE_XINERAMA
@@ -157,6 +162,9 @@ screen_get_sel(void)
XChangeProperty(dpy, ROOT, net_atom[wmfs_current_screen], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&selscreen, 1);
if(os != selscreen)
prevselscreen = os;
return selscreen;
}
@@ -166,11 +174,12 @@ void
screen_init_geo(void)
{
int i;
int s = screen_count();
sgeo = emalloc(screen_count(), sizeof(XRectangle));
spgeo = emalloc(screen_count(), sizeof(XRectangle));
sgeo = emalloc(s, sizeof(XRectangle));
spgeo = emalloc(s, sizeof(XRectangle));
for(i = 0; i < screen_count(); ++i)
for(i = 0; i < s; ++i)
sgeo[i] = screen_get_geo(i);
spgeo[0].x = 0;
@@ -250,3 +259,18 @@ uicb_screen_prev(uicb_t cmd)
return;
}
/** Uicb: screen prev sel
* \param cmd uicb_t type unused
*/
void
uicb_screen_prev_sel(uicb_t cmd)
{
screen_get_sel();
screen_set_sel(prevselscreen);
return;
}

237
src/status.c Normal file
View File

@@ -0,0 +1,237 @@
/*
* status.c
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h"
/** Check rectangles blocks in str and return properties
* --> \b[x;y;width;height;#color]\
*\param r StatusRec pointer, rectangles properties
*\param str String
*\return n Length of r
*/
int
statustext_rectangle(StatusRec *r, char *str)
{
char as;
int n, i, j, k;
for(i = j = n = 0; i < strlen(str); ++i, ++j)
if(sscanf(&str[i], "\\b[%d;%d;%d;%d;#%x]%c", &r[n].x, &r[n].y, &r[n].w, &r[n].h, &r[n].color, &as) == 6
&& as == '\\')
for(++n, ++i, --j; str[i] != as || str[i - 1] != ']'; ++i);
else if(j != i)
str[j] = str[i];
for(k = j; k < i; str[k++] = 0);
return n;
}
/** Check graphs blocks in str and return properties
* --> \g[x;y;width;height;#color;data]\
*\param g StatusGraph pointer, graphs properties
*\param str String
*\return n Length of g
*/
int
statustext_graph(StatusGraph *g, char *str)
{
char as, c, *p;
int n, i, j, k, m, w;
for(i = j = n = 0; i < strlen(str); ++i, ++j)
if(sscanf(&str[i], "\\g[%d;%d;%d;%d;#%x;%512[^]]]%c",
&g[n].x, &g[n].y, &g[n].w, &g[n].h, &g[n].color, g[n].data, &as) == 7
&& as == '\\')
{
/* data is a list of numbers separated by ';' */
w = g[n].w;
p = strtok(g[n].data, ";");
m = 0;
while(p && m < w)
{
c = atoi(p);
/* height limits */
if(c < 0)
c = 0;
if(c > g[n].h)
c = g[n].h;
g[n].data[m] = c;
p = strtok(NULL, ";");
++m;
}
/* width limits */
for(; m < w; ++m)
g[n].data[m] = 0;
/* data is a array[w] of bytes now */
for(++n, ++i, --j; str[i] != as || str[i - 1] != ']'; ++i);
}
else if(j != i)
str[j] = str[i];
for(k = j; k < i; str[k++] = 0);
return n;
}
/** Check text blocks in str and return properties
* --> \s[x;y;#color;text]\
*\param s StatusText pointer, text properties
*\param str String
*\return n Length of s
*/
int
statustext_text(StatusText *s, char *str)
{
char as;
int n, i, j, k;
for(i = j = n = 0; i < strlen(str); ++i, ++j)
if(sscanf(&str[i], "\\s[%d;%d;%7[^;];%512[^]]]%c", &s[n].x, &s[n].y, s[n].color, s[n].text, &as) == 5
&& as == '\\')
for(++n, ++i, --j; str[i] != as || str[i - 1] != ']'; ++i);
else if(j != i)
str[j] = str[i];
for(k = j; k < i; str[k++] = 0);
return n;
}
/** Draw normal text and colored normal text
* --> \#color\ text in color
*\param sc Screen
*\param str String
*/
void
statustext_normal(int sc, char *str)
{
char strwc[MAXSTATUS] = { 0 };
char buf[MAXSTATUS] = { 0 };
char col[8] = { 0 };
int n, i, j, k;
for(i = j = n = 0; i < strlen(str); ++i, ++j)
if(str[i] == '\\' && str[i + 1] == '#' && str[i + 8] == '\\')
{
++n;
i += 8;
--j;
}
else
strwc[j] = str[i];
/* Draw normal text without any blocks */
draw_text(infobar[sc].bar->dr, (sgeo[sc].width - SHADH) - textw(strwc),
FHINFOBAR, infobar[sc].bar->fg, 0, strwc);
if(n)
{
strcpy(buf, strwc);
for(i = k = 0; i < strlen(str); ++i, ++k)
if(str[i] == '\\' && str[i + 1] == '#' && str[i + 8] == '\\')
{
/* Store current color in col[] */
for(j = 0, ++i; str[i] != '\\'; col[j++] = str[i++]);
/* Draw a rectangle with the bar color to draw the text properly */
draw_rectangle(infobar[sc].bar->dr, (sgeo[sc].width - SHADH) - textw(&buf[k]),
0, INFOBARH - (sgeo[sc].width - SHADH) - textw(&buf[k]),
INFOBARH, conf.colors.bar);
/* Draw text with its color */
draw_text(infobar[sc].bar->dr, (sgeo[sc].width - SHADH) - textw(&buf[k]),
FHINFOBAR, col, 0, &buf[k]);
strcpy(buf, strwc);
++i;
}
}
return;
}
/** Handle statustext and draw all things in infobar of specified screen
*\param sc Screen number
*\param str String
*/
void
statustext_handle(int sc, char *str)
{
char *lastst;
int i, nr, ng, ns, len;
StatusRec r[128];
StatusGraph g[128];
StatusText s[128];
/* If the str == the current statustext, return (not needed) */
if(!str)
return;
barwin_refresh_color(infobar[sc].bar);
/* save last status text address (for free at the end) */
lastst = infobar[sc].statustext;
infobar[sc].statustext = _strdup(str);
len = ((strlen(str) > MAXSTATUS) ? MAXSTATUS : strlen(str));
/* Store rectangles, located text & images properties. */
nr = statustext_rectangle(r, str);
ng = statustext_graph(g, str);
ns = statustext_text(s, str);
/* Draw normal text (and possibly colored with \#color\ blocks) */
statustext_normal(sc, str);
/* Draw rectangles with stored properties. */
for(i = 0; i < nr; ++i)
draw_rectangle(infobar[sc].bar->dr, r[i].x, r[i].y, r[i].w, r[i].h, r[i].color);
/* Draw graphs with stored properties. */
for(i = 0; i < ng; ++i)
draw_graph(infobar[sc].bar->dr, g[i].x, g[i].y, g[i].w, g[i].h, g[i].color, g[i].data);
/* Draw located text with stored properties. */
for(i = 0; i < ns; ++i)
draw_text(infobar[sc].bar->dr, s[i].x, s[i].y, s[i].color, 0, s[i].text);
barwin_refresh(infobar[sc].bar);
free(lastst);
return;
}

View File

@@ -38,17 +38,21 @@
#define NBUTTON 8
#define MAXTAG 36
#define NUM_OF_LAYOUT 10
#define HISTOLEN 128
/* Clients flags definition */
#define FreeFlag (1 << 1)
#define MaxFlag (1 << 2)
#define TileFlag (1 << 3)
#define HideFlag (1 << 4)
#define LMaxFlag (1 << 5)
#define UnmapFlag (1 << 6)
#define HintFlag (1 << 7)
#define FSSFlag (1 << 8)
#define AboveFlag (1 << 9)
#define FreeFlag (1 << 1)
#define MaxFlag (1 << 2)
#define TileFlag (1 << 3)
#define HideFlag (1 << 4)
#define LMaxFlag (1 << 5)
#define UnmapFlag (1 << 6)
#define HintFlag (1 << 7)
#define FSSFlag (1 << 8)
#define AboveFlag (1 << 9)
#define UrgentFlag (1 << 10)
#define TagFlag(t) (1 << (t))
/* XEMBED messages */
#define XEMBED_MAPPED (1 << 0)
@@ -81,13 +85,16 @@ typedef unsigned char uchar;
/* Enum */
enum { CurNormal, CurResize, CurRightResize, CurLeftResize, CurMove, CurLast };
enum { TagSel, TagTransfert, TagAdd, TagNext, TagPrev, TagActionLast };
/* Menu align */
enum { MA_Center = 0, MA_Left = 1, MA_Right = 2 };
/* Infobar position */
enum { IB_Hide = 0, IB_Bottom = 1, IB_Top = 2 };
typedef enum { Right, Left, Top, Bottom, Center, PositionLast } Position;
/* Ewmh hints list */
enum
{
@@ -176,6 +183,8 @@ struct Client
XRectangle frame_geo;
/* Old window attribute */
XRectangle ogeo;
/* Free window attribute */
XRectangle free_geo;
/* For resizehint usage */
int basew, baseh, incw, inch;
int maxw, maxh, minw, minh;
@@ -224,18 +233,20 @@ typedef struct
/* InfoBar Struct */
typedef struct
{
BarWindow *bar;
BarWindow *bar, *selbar;
BarWindow *layout_button;
BarWindow *tags[MAXTAG];
BarWindow *tags_board, *tags[MAXTAG];
XRectangle geo;
int position;
char *statustext;
Bool need_update;
} InfoBar;
/* Layout Structure */
typedef struct
{
char *symbol;
char *type;
void (*func)(int screen);
} Layout;
@@ -248,11 +259,15 @@ typedef struct
int layers;
float mwfact;
int nmaster;
Bool urgent;
Bool resizehint;
Bool request_update;
Bool abovefc;
int barpos;
Layout layout;
uint tagad;
MouseBinding *mouse;
int nmouse;
} Tag;
/* Menu Item Struct */
@@ -261,6 +276,8 @@ typedef struct
char *name;
void (*func)(uicb_t);
uicb_t cmd;
Bool (*check)(uicb_t);
char *submenu;
} MenuItem;
/* Menu Struct */
@@ -273,6 +290,7 @@ typedef struct
char *name;
/* Placement */
Bool place_at_mouse;
int align;
int x, y;
/* Color */
struct
@@ -292,6 +310,8 @@ typedef struct
char *name;
char *prompt;
char *command;
char histo[HISTOLEN][512];
uint nhisto;
} Launcher;
/* Button struct */
@@ -301,6 +321,7 @@ typedef struct
XSegment *linecoord;
int nlines;
int nmouse;
uint flags;
} Button;
/* Alias struct */
@@ -321,8 +342,15 @@ typedef struct
Bool raisefocus;
Bool raiseswitch;
Bool focus_fmouse;
Bool focus_pclick;
Bool ignore_next_client_rules;
Bool tagautohide;
uint pad;
int status_timing;
char *status_path;
pid_t status_pid;
char *autostart_path;
char *autostart_command;
struct
{
/*
@@ -332,6 +360,8 @@ typedef struct
uint bar;
char *text;
char *tagselfg;
char *tagurfg;
uint tagurbg;
uint tagselbg;
uint tag_occupied_bg;
uint tagbord;
@@ -343,8 +373,17 @@ typedef struct
int height;
MouseBinding *mouse;
int nmouse;
Bool selbar;
} bars;
struct
{
char *fg;
uint bg;
int maxlenght;
MouseBinding *mouse;
int nmouse;
} selbar;
struct
{
char *background_command;
MouseBinding *mouse;
@@ -386,12 +425,15 @@ typedef struct
Bool layout;
} border;
Alias alias[256];
uint mouse_tag_action[TagActionLast];
Layout layout[NUM_OF_LAYOUT];
Menu *menu;
Launcher *launcher;
int *ntag;
Bool tag_round;
Bool client_round;
Bool layout_system; /* Switch: False, Menu: True. */
Bool layout_placement; /* Right (normal): False, Left: True. */
/* Number of... */
int nkeybind;
int nlayout;
@@ -399,6 +441,32 @@ typedef struct
int nlauncher;
} Conf;
typedef struct
{
uint x, y, w, h;
uint color;
} StatusRec;
typedef struct
{
uint x, y, w, h;
uint color;
char data[512];
} StatusGraph;
typedef struct
{
uint x, y;
char color[8];
char text[512];
} StatusText;
typedef struct
{
uint x, y, w, h;
char name[512];
} ImageAttr;
/* Config.c struct */
typedef struct
{

415
src/tag.c
View File

@@ -28,7 +28,6 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h"
@@ -39,12 +38,13 @@
void
tag_set(int tag)
{
int otag;
Client *c;
Bool al = False;
int i;
screen_get_sel();
otag = seltag[selscreen];
prevseltag[selscreen] = seltag[selscreen];
if(conf.tag_round)
{
@@ -60,16 +60,36 @@ tag_set(int tag)
if(!tag || tag == seltag[selscreen]
|| tag > conf.ntag[selscreen])
return;
seltag[selscreen] = tag;
}
ewmh_update_current_tag_prop();
/* Arrange infobar position */
if(tags[selscreen][otag].barpos != tags[selscreen][seltag[selscreen]].barpos)
if(tags[selscreen][prevseltag[selscreen]].barpos != tags[selscreen][seltag[selscreen]].barpos)
infobar_set_position(tags[selscreen][seltag[selscreen]].barpos);
arrange(selscreen, False);
/* Check if a layout update is needed with additional tags */
if(tags[selscreen][seltag[selscreen]].tagad)
al = True;
for(i = 1; i < conf.ntag[selscreen] + 1; ++i)
if(tags[selscreen][i].tagad & TagFlag(seltag[selscreen]))
{
al = True;
break;
}
/* Check for ignore_tag clients */
for(c = clients; c; c = c->next)
if(c->tag == MAXTAG + 1 && c->screen == selscreen)
{
al = True;
break;
}
arrange(selscreen, al);
if(tags[selscreen][tag].request_update)
{
@@ -101,12 +121,15 @@ tag_transfert(Client *c, int tag)
if(!tag)
tag = 1;
if(tag > conf.ntag[selscreen])
return;
c->tag = tag;
c->screen = selscreen;
arrange(c->screen, True);
if(c == sel)
if(c == sel && c->tag != tag)
client_focus(NULL);
client_update_attributes(c);
@@ -158,6 +181,92 @@ uicb_tag_prev(uicb_t cmd)
return;
}
/** Set the next visible tag
* \param cmd uicb_t type unused
*/
void
uicb_tag_next_visible(uicb_t cmd)
{
int i, tag;
Client *c;
Bool is_occupied[MAXTAG];
screen_get_sel();
if(!conf.tagautohide)
{
tag_set(seltag[selscreen] + 1);
return;
}
for(i = 0; i < MAXTAG; i++)
is_occupied[i] = False;
for(c = clients; c; c = c->next)
if(c->screen == selscreen)
is_occupied[c->tag] = True;
for(tag = seltag[selscreen] + 1; tag < conf.ntag[selscreen] + 1; ++tag)
if(is_occupied[tag])
{
tag_set(tag);
return;
}
if(conf.tag_round)
for(tag = 0; tag < seltag[selscreen]; ++tag)
if(is_occupied[tag])
{
tag_set(tag);
return;
}
return;
}
/** Set the prev visible tag
* \param cmd uicb_t type unused
*/
void
uicb_tag_prev_visible(uicb_t cmd)
{
int i, tag;
Client *c;
Bool is_occupied[MAXTAG];
screen_get_sel();
if(!conf.tagautohide)
{
tag_set(seltag[selscreen] - 1);
return;
}
for(i = 0; i < MAXTAG; i++)
is_occupied[i] = False;
for(c = clients; c; c = c->next)
if(c->screen == selscreen)
is_occupied[c->tag] = True;
for(tag = seltag[selscreen] - 1; tag >= 0; --tag)
if(is_occupied[tag])
{
tag_set(tag);
return;
}
if(conf.tag_round)
for(tag = conf.ntag[selscreen]; tag > seltag[selscreen]; --tag)
if(is_occupied[tag])
{
tag_set(tag);
return;
}
return;
}
/** Transfert the selected client to
* the wanted tag
* \param cmd Wanted tag, uicb_t type
@@ -171,3 +280,297 @@ uicb_tagtransfert(uicb_t cmd)
return;
}
/** Set the previous selected tag
* \param cmd uicb_t type unused
*/
void
uicb_tag_prev_sel(uicb_t cmd)
{
screen_get_sel();
tag_set(prevseltag[selscreen]);
return;
}
/** Transfert the selected client to the next tag
* \param cmd uicb_t type unused
*/
void
uicb_tagtransfert_next(uicb_t cmd)
{
CHECK(sel);
int tag = seltag[selscreen] + 1;
if(tag > conf.ntag[selscreen])
{
if(!conf.tag_round)
return;
tag = 1;
}
tag_transfert(sel, tag);
return;
}
/** Transfert the selected client to the prev tag
* \param cmd uicb_t type unused
*/
void
uicb_tagtransfert_prev(uicb_t cmd)
{
CHECK(sel);
int tag = seltag[selscreen] - 1;
if(tag <= 0)
{
if(!conf.tag_round)
return;
tag = conf.ntag[selscreen];
}
tag_transfert(sel, tag);
return;
}
/** Go to the current urgent tag
*\param cmd uicb_t type unused
*/
void
uicb_tag_urgent(uicb_t cmd)
{
Client *c;
Bool b = False;
/* Check if there is a urgent client */
for(c = clients; c; c = c->next)
if(c->flags & UrgentFlag)
{
b = True;
break;
}
if(!b)
return;
screen_set_sel(c->screen);
tag_set(c->tag);
client_focus(c);
return;
}
/** Add an additional tag to the current tag
*\param sc Screen
*\param tag Tag where apply additional tag
*\param adtag Additional tag to apply in tag
*/
void
tag_additional(int sc, int tag, int adtag)
{
if(tag < 0 || tag > conf.ntag[sc]
|| adtag < 1 || adtag > conf.ntag[sc] || adtag == seltag[sc])
return;
tags[sc][tag].tagad ^= TagFlag(adtag);
tags[sc][adtag].request_update = True;
arrange(sc, True);
return;
}
/** Add an additional tag to the current tag
*\param cmd uicb_t
*/
void
uicb_tag_toggle_additional(uicb_t cmd)
{
screen_get_sel();
tag_additional(selscreen, seltag[selscreen], atoi(cmd));
return;
}
/** Swap 2 tags
*\param s Screen
*\param t1 Tag 1
*\param t2 Tag 2
*/
void
tag_swap(int s, int t1, int t2)
{
Client *c;
Tag t;
if(t1 > conf.ntag[s] || t1 < 1
|| t2 > conf.ntag[s] || t2 < 1 || t1 == t2)
return;
t = tags[s][t1];
tags[s][t1] = tags[s][t2];
tags[s][t2] = t;
for(c = clients; c; c = c->next)
{
if(c->screen == s && c->tag == t1)
c->tag = t2;
else if(c->screen == s && c->tag == t2)
c->tag = t1;
}
infobar_update_taglist(s);
tag_set(t2);
return;
}
/** Swap current tag with a specified tag
*\param cmd uicb_t type
*/
void
uicb_tag_swap(uicb_t cmd)
{
screen_get_sel();
tag_swap(selscreen, seltag[selscreen], atoi(cmd));
return;
}
/** Swap current tag with next tag
*\param cmd uicb_t type
*/
void
uicb_tag_swap_next(uicb_t cmd)
{
screen_get_sel();
tag_swap(selscreen, seltag[selscreen], seltag[selscreen] + 1);
return;
}
/** Swap current tag with previous tag
*\param cmd uicb_t type
*/
void
uicb_tag_swap_previous(uicb_t cmd)
{
screen_get_sel();
tag_swap(selscreen, seltag[selscreen], seltag[selscreen] - 1);
return;
}
/** Adding a tag
*\param s Screen number
*\param name New tag name
*/
void
tag_new(int s, char *name)
{
Tag t = { NULL, NULL, 0, 0, 0.65, 1, False, False, False, False, IB_Top,
layout_name_to_struct(conf.layout, "tile_right", conf.nlayout, layout_list), 0, NULL, 0 };
if(conf.ntag[s] + 1 > MAXTAG)
{
warnx("Too many tag: Can't create new tag");
return;
}
++conf.ntag[s];
tags[s][conf.ntag[s]] = t;
tags[s][conf.ntag[s]].name = _strdup((name ? name : "new tag"));
infobar_update_taglist(s);
infobar_draw(s);
tag_set(conf.ntag[s]);
return;
}
/** Adding a tag
*\param cmd uicb_t type
*/
void
uicb_tag_new(uicb_t cmd)
{
screen_get_sel();
tag_new(selscreen, (char*)cmd);
return;
}
/** Delete a tag
*\param s Screen number
*\param tag Tag number
*/
void
tag_delete(int s, int tag)
{
Tag t = { 0 };
Client *c;
int i;
if(tag < 0 || tag > conf.ntag[s] || conf.ntag[s] == 1)
return;
for(c = clients; c; c = c->next)
if(c->screen == s && c->tag == tag)
{
warnx("Client(s) present in this tag, can't delete it");
return;
}
--conf.ntag[s];
tags[s][tag] = t;
infobar[s].tags[tag] = NULL;
for(i = tag; i < conf.ntag[s] + 1; ++i)
{
/* Set clients tag because of shift */
for(c = clients; c; c = c->next)
if(c->screen == s && c->tag == i + 1)
c->tag = i;
/* shift */
tags[s][i] = tags[s][i + 1];
}
infobar[s].need_update = True;
infobar_update_taglist(s);
infobar_draw(s);
if(tag == seltag[s])
tag_set(tag <= conf.ntag[s] ? tag : conf.ntag[s]);
return;
}
/** Delete a tag
*\param cmd uicb_t type
*/
void
uicb_tag_del(uicb_t cmd)
{
int n;
screen_get_sel();
if(cmd == NULL || !(n = atoi(cmd)))
n = seltag[selscreen];
tag_delete(selscreen, n);
return;
}

View File

@@ -111,7 +111,7 @@ _strdup(const char *str)
usage. {{{
*/
void*
name_to_func(char *name, func_name_list_t *l)
name_to_func(char *name, const func_name_list_t *l)
{
int i;
@@ -150,7 +150,7 @@ char_to_button(char *name, name_to_uint_t blist[])
}
Layout
layout_name_to_struct(Layout lt[], char *name, int n, func_name_list_t llist[])
layout_name_to_struct(Layout lt[], char *name, int n, const func_name_list_t llist[])
{
int i;
@@ -200,44 +200,69 @@ get_mouse_pos(void)
/** Execute a sh command
* \param cmd Command
* \return child pid
*/
void
int
spawn(const char *format, ...)
{
char *sh = NULL;
char cmd[512];
va_list ap;
if(strlen(format) > 511)
{
warnx("spawn(): Error, command too long.");
return;
}
pid_t pid, ret;
int p[2], len;
va_start(ap, format);
vsprintf(cmd, format, ap);
len = vsnprintf(cmd, sizeof(cmd), format, ap);
va_end(ap);
if(!strlen(cmd))
return;
if (len >= sizeof(cmd))
{
warnx("command too long (> 512 bytes)");
return -1;
}
if(!(sh = getenv("SHELL")))
sh = "/bin/sh";
if(fork() == 0)
if (pipe(p) == -1)
{
if(fork() == 0)
warn("pipe");
return -1;
}
if((pid = fork()) == 0)
{
close(p[0]);
if((pid = fork()) == 0)
{
if(dpy)
close(ConnectionNumber(dpy));
setsid();
execl(sh, sh, "-c", cmd, (char*)NULL);
exit(EXIT_SUCCESS);
exit(EXIT_FAILURE);
}
write(p[1], &pid, sizeof(pid_t));
close(p[1]);
exit(EXIT_SUCCESS);
}
else if (pid != -1)
{
close(p[1]);
if (sizeof(pid_t) != read(p[0], &ret, sizeof(pid_t)))
{
warn("read");
ret = -1;
}
close(p[0]);
waitpid(pid, NULL, 0);
}
else
{
warn("fork");
ret = -1;
}
return;
return ret;
}
/** Swap two pointer.
@@ -262,4 +287,56 @@ void
uicb_spawn(uicb_t cmd)
{
spawn("%s", cmd);
return;
}
#ifdef HAVE_IMLIB
/** Check images blocks in str and return properties
* --> \i[x;y;w;h;name]\
*\param im ImageAttr pointer, image properties
*\param str String
*\return n Lenght of i
*/
int
parse_image_block(ImageAttr *im, char *str)
{
char as;
int n, i, j, k;
for(i = j = n = 0; i < strlen(str); ++i, ++j)
if(sscanf(&str[i], "\\i[%d;%d;%d;%d;%512[^]]]%c", &im[n].x, &im[n].y, &im[n].w, &im[n].h, im[n].name, &as) == 6
&& as == '\\')
for(++n, ++i, --j; str[i] != as || str[i - 1] != ']'; ++i);
else if(j != i)
str[j] = str[i];
for(k = j; k < i; str[k++] = 0);
return n;
}
#endif /* HAVE_IMLIB */
char*
clean_value(char *str)
{
int i;
char c, *p;
if(!str || !(p = _strdup(str)))
return NULL;
/* Remove useless spaces */
for(; *p == ' '; ++p);
for(; *(p + strlen(p) - 1) == ' '; *(p + strlen(p) - 1) = '\0');
/* For string delimiter (" or ') */
if(((c = *p) == '"' || (c = *p) == '\'') && strchr(p + 1, c))
{
for(++p, i = 0; p[i] && p[i] != c; ++i);
p[i] = '\0';
}
return p;
}

View File

@@ -49,6 +49,8 @@ vicmd_to_uicb vicmd[] =
{"sp", "screen_prev"},
{"cc", "client_kill"},
{"ct", "tag_transfert"},
{"ctn", "tag_transfert_next"},
{"ctp", "tag_transfert_prev"},
{"cn", "client_next"},
{"cp", "client_prev"},
{"csn", "client_swap_next"},

View File

@@ -103,7 +103,6 @@ quit(void)
IFREE(infobar);
IFREE(keys);
IFREE(func_list);
IFREE(layout_list);
IFREE(net_atom);
/* Clean conf alloced thing */
@@ -117,22 +116,22 @@ quit(void)
}
IFREE(conf.launcher);
IFREE(conf.ntag);
IFREE(conf.titlebar.mouse);
for(i = 0; i < conf.titlebar.nbutton; ++i)
{
IFREE(conf.titlebar.button[i].mouse);
IFREE(conf.titlebar.button[i].linecoord);
}
IFREE(conf.bars.mouse);
IFREE(conf.selbar.mouse);
IFREE(conf.titlebar.button);
IFREE(conf.client.mouse);
IFREE(conf.root.mouse);
free_conf(NULL);
XSync(dpy, False);
XCloseDisplay(dpy);
/* kill status script */
if (conf.status_pid != (pid_t)-1)
kill(conf.status_pid, SIGQUIT);
return;
}
@@ -142,25 +141,22 @@ thread_process(void *arg)
XEvent ev;
/* X event loop */
if(!(int*)arg)
if(arg)
{
while(!exiting && !XNextEvent(dpy, &ev))
getevent(ev);
pthread_exit(0);
}
/* Status checking loop with timing */
else
{
while(!exiting)
pthread_detach(pthread_self());
do
{
spawn(status_path);
conf.status_pid = spawn(conf.status_path);
sleep(conf.status_timing);
}
pthread_exit(0);
} while (!exiting && conf.status_timing != 0);
}
pthread_exit(NULL);
}
/** WMFS main loop.
@@ -181,7 +177,6 @@ mainloop(void)
pthread_create(&evstatus, NULL, thread_process, NULL);
(void)pthread_join(evloop, &ret);
(void)pthread_join(evstatus, &ret);
}
return;
@@ -210,11 +205,13 @@ scan(void)
XWindowAttributes wa;
Window usl, usl2, *w = NULL;
Atom rt;
int rf, tag = -1, screen = -1, free = -1;
int s, rf, tag = -1, screen = -1, free = -1;
ulong ir, il;
uchar *ret;
Client *c;
s = screen_count();
if(XQueryTree(dpy, ROOT, &usl, &usl2, &w, &n))
for(i = n - 1; i != -1; --i)
if(XGetWindowAttributes(dpy, w[i], &wa)
@@ -244,9 +241,9 @@ scan(void)
c = client_manage(w[i], &wa, False);
if(tag != -1)
if(tag != -1 && tag != MAXTAG + 1)
c->tag = tag;
if(screen != -1 && screen <= screen_count() - 1)
if(screen != -1 && screen <= s - 1)
c->screen = screen;
if(free != -1)
c->flags |= (free) ? FreeFlag : 0;
@@ -262,7 +259,7 @@ scan(void)
tags[c->screen][c->tag].request_update = True;
}
for(i = 0; i < screen_count(); ++i)
for(i = 0; i < s; ++i)
arrange(i, True);
XFree(w);
@@ -477,7 +474,7 @@ main(int argc, char **argv)
break;
case 'c':
exec_uicb_function(argv[2], ((argv[3]) ? argv[3] : NULL));
exec_uicb_function(optarg, argv[optind]);
XCloseDisplay(dpy);
exit(EXIT_SUCCESS);
break;

View File

@@ -33,6 +33,8 @@
#ifndef WMFS_H
#define WMFS_H
#define _BSD_SOURCE /* vsnprintf */
#define _POSIX_SOURCE /* kill */
/* Lib headers */
#include <stdio.h>
#include <stdlib.h>
@@ -40,6 +42,8 @@
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
#include <time.h>
#include <getopt.h>
#include <dirent.h>
@@ -55,7 +59,7 @@
#include <X11/Xft/Xft.h>
/* Local headers */
#include "confparse/confparse.h"
#include "parse/parse.h"
#include "config.h"
#include "structs.h"
@@ -68,6 +72,10 @@
#include <X11/extensions/Xrandr.h>
#endif /* HAVE_XRANDR */
#ifdef HAVE_IMLIB
#include <Imlib2.h>
#endif /* HAVE_IMLIB */
/* MACRO */
#define ButtonMask (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask)
#define MouseMask (ButtonMask | PointerMotionMask)
@@ -82,11 +90,12 @@
#define SHADC (0x000000) /* 'Cause i don't know how darken a color yet */
#define BORDH conf.client.borderheight
#define TBARH ((conf.titlebar.height < BORDH) ? BORDH : conf.titlebar.height)
#define RESHW (6 * BORDH)
#define RESHW (6 * (BORDH))
#define BUTTONWH (TBARH / 2)
#define DEF_CONF ".config/wmfs/wmfsrc"
#define DEF_STATUS ".config/wmfs/status.sh"
#define PAD conf.pad
#define MAXSTATUS (4096)
#define CWIN(win, parent, x, y, w, h, b, mask, col, at) \
do { \
@@ -102,6 +111,7 @@
#define CHECK(x) if(!(x)) return
#define IFREE(x) if(x) free(x)
#define LEN(x) (sizeof(x) / sizeof((x)[0]))
#define MAXCLIST (64)
/* barwin.c */
BarWindow *barwin_create(Window parent,
@@ -126,17 +136,25 @@ void barwin_refresh(BarWindow *bw);
/* draw.c */
void draw_text(Drawable d, int x, int y, char* fg, int pad, char *str);
void draw_rectangle(Drawable dr, int x, int y, uint w, uint h, uint color);
ushort textw(const char *text);
void draw_graph(Drawable dr, int x, int y, uint w, uint h, uint color, char *data);
#ifdef HAVE_IMLIB
void draw_image(Drawable dr, int x, int y, int w, int h, char *name);
#endif /* HAVE_IMLIB */
ushort textw(char *text);
/* infobar.c */
void infobar_init(void);
void infobar_draw(int sc);
void infobar_draw_layout(int sc);
void infobar_draw_selbar(int sc);
void infobar_draw_taglist(int sc);
void infobar_draw_statustext(int sc, char *str);
void infobar_update_taglist(int sc);
void infobar_destroy(void);
void infobar_set_position(int pos);
void uicb_infobar_togglepos(uicb_t);
void uicb_toggle_tagautohide(uicb_t);
/* client.c */
void client_attach(Client *c);
@@ -180,6 +198,11 @@ void uicb_client_screen_next(uicb_t);
void uicb_client_screen_prev(uicb_t);
void uicb_client_move(uicb_t cmd);
void uicb_client_resize(uicb_t cmd);
void uicb_ignore_next_client_rules(uicb_t cmd);
void uicb_clientlist(uicb_t cmd);
void uicb_client_select(uicb_t cmd);
Bool uicb_checkclist(uicb_t);
void uicb_client_ignore_tag(uicb_t);
/* ewmh.c */
void ewmh_init_hints(void);
@@ -223,13 +246,15 @@ void menu_init(Menu *menu, char *name, int nitem, uint bg_f, char *fg_f, uint bg
void menu_new_item(MenuItem *mi, char *name, void *func, char *cmd);
void menu_draw(Menu menu, int x, int y);
Bool menu_manage_event(XEvent *ev, Menu *menu, BarWindow *winitem[]);
Bool menu_activate_item(Menu *menu, int i);
void menu_focus_item(Menu *menu, int item, BarWindow *winitem[]);
void menu_draw_item_name(Menu *menu, int item, BarWindow *winitem[]);
int menu_get_longer_string(MenuItem *mt, int nitem);
int menu_get_longer_string(MenuItem *mi, int nitem);
void uicb_menu(uicb_t cmd);
void menu_clear(Menu *menu);
/* launcher.c */
void launcher_execute(Launcher launcher);
void launcher_execute(Launcher *launcher);
void uicb_launcher(uicb_t);
/* mouse.c */
@@ -249,17 +274,22 @@ long getcolor(char *color);
void setwinstate(Window win, long state);
char* _strdup(char const *str);
/* Conf usage {{{ */
void* name_to_func(char *name, func_name_list_t *l);
void* name_to_func(char *name, const func_name_list_t *l);
ulong char_to_modkey(char *name, key_name_list_t key_l[]);
uint char_to_button(char *name, name_to_uint_t blist[]);
Layout layout_name_to_struct(Layout lt[], char *name, int n, func_name_list_t llist[]);
Layout layout_name_to_struct(Layout lt[], char *name, int n, const func_name_list_t llist[]);
char* alias_to_str(char *conf_choice);
/* }}} */
XRectangle get_mouse_pos(void);
char *char_to_str(const char c);
void spawn(const char *str, ...);
int spawn(const char *str, ...);
void swap_ptr(void **x, void **y);
void uicb_spawn(uicb_t);
char *clean_value(char *str);
#ifdef HAVE_IMLIB
int parse_image_block(ImageAttr *im, char *str);
#endif /* HAVE_IMLIB */
/* tag.c */
void tag_set(int tag);
@@ -267,7 +297,23 @@ void tag_transfert(Client *c, int tag);
void uicb_tag(uicb_t);
void uicb_tag_next(uicb_t);
void uicb_tag_prev(uicb_t);
void uicb_tag_next_visible(uicb_t);
void uicb_tag_prev_visible(uicb_t);
void uicb_tagtransfert(uicb_t);
void uicb_tag_prev_sel(uicb_t);
void uicb_tagtransfert_next(uicb_t);
void uicb_tagtransfert_prev(uicb_t);
void uicb_tag_urgent(uicb_t cmd);
void tag_additional(int sc, int tag, int adtag);
void uicb_tag_toggle_additional(uicb_t);
void tag_swap(int s, int t1, int t2);
void uicb_tag_swap(uicb_t);
void uicb_tag_swap_next(uicb_t);
void uicb_tag_swap_previous(uicb_t);
void tag_new(int s, char *name);
void uicb_tag_new(uicb_t);
void tag_delete(int s, int tag);
void uicb_tag_del(uicb_t);
/* screen.c */
int screen_count(void);
@@ -279,6 +325,14 @@ void screen_init_geo(void);
void uicb_screen_select(uicb_t);
void uicb_screen_next(uicb_t);
void uicb_screen_prev(uicb_t);
void uicb_screen_prev_sel(uicb_t);
/* status.c */
int statustext_rectangle(StatusRec *r, char *str);
int statustext_graph(StatusGraph *g, char *str);
int statustext_text(StatusText *s, char *str);
void statustext_normal(int sc, char *str);
void statustext_handle(int sc, char *str);
/* layout.c */
void arrange(int screen, Bool update_layout);
@@ -308,11 +362,13 @@ void uicb_toggle_abovefc(uicb_t cmd);
void uicb_set_layer(uicb_t cmd);
void uicb_set_client_layer(uicb_t cmd);
void layout_set_client_master(Client *c);
Bool uicb_checkmax(uicb_t);
Bool uicb_checkfree(uicb_t);
Bool uicb_checklayout(uicb_t);
/* init.c */
void init(void);
void init_root(void);
void init_layout(void);
void init_font(void);
void init_gc(void);
void init_cursor(void);
@@ -352,13 +408,14 @@ void uicb_reload(uicb_t);
Display *dpy;
GC gc, gc_stipple;
int selscreen;
int prevselscreen;
Conf conf;
Key *keys;
Bool exiting, estatus;
XRectangle *sgeo;
XRectangle *spgeo;
Cursor cursor[CurLast];
char *argv_global, *status_path;
char *argv_global;
int xrandr_event;
uint timing;
@@ -372,15 +429,23 @@ Atom *net_atom;
InfoBar *infobar;
Tag **tags;
int *seltag;
int *prevseltag;
Menu menulayout;
/* ClientList */
Menu clientlist;
struct clndx {
char key[4];
Client *client;
} clist_index[MAXCLIST];
/* Important Client */
Client *clients;
Client *sel;
/* Other */
func_name_list_t *func_list;
func_name_list_t *layout_list;
extern const func_name_list_t layout_list[];
uint numlockmask;
#endif /* WMFS_H */

View File

@@ -7,12 +7,32 @@
font = "dejavu-10"
raisefocus = false
focus_follow_mouse = true
# focus_pointer_click: click on unfocused client area:
# true -- default, set focus
# false -- click go to client; including dockapps
focus_pointer_click = true
status_timing = 1 #seconds
[/misc]
[bar]
bg = "#191919"
fg = "#D4D4D4"
border = true
# selbar = false #not worked now, see section [selbar]
# Remove this section to disable the selbar.
[selbar]
bg = "#191919"
fg = "#D4D4ff"
# Cut title lenght
# max_lenght = 25
[mouse] button = "3" func = "clientlist" [/mouse]
[mouse] button = "4" func = "client_next" [/mouse]
[mouse] button = "5" func = "client_prev" [/mouse]
[/selbar]
[/bar]
[layouts]
@@ -25,6 +45,9 @@
# Value menu or switch.
system = "menu"
# Value left or right.
placement = "right"
# Tiling layouts.
[layout] type = "tile_right" symbol = "RIGHT" [/layout]
[layout] type = "tile_left" symbol = "LEFT" [/layout]
@@ -45,10 +68,22 @@
occupied_bg = "#003366"
sel_fg = "#191919"
sel_bg = "#7E89A2"
urgent_bg = "#DD1111"
urgent_fg = "#000000"
# Border around the tag buttons.
border = true
# Hide empty tags in tag list
autohide = false
# Mouse buttons action on tag.
mouse_button_tag_sel = "1"
mouse_button_tag_transfert = "2"
mouse_button_tag_add = "3"
mouse_button_tag_next = "4"
mouse_button_tag_prev = "5"
[tag]
name = "one"
screen = 0
@@ -57,6 +92,8 @@
layout = "tile_right"
resizehint = false
infobar_position = "top"
#[mouse] [/mouse] Possible multi mouse section
[/tag]
[tag] name = "two" clients = {"Browser"} [/tag]
@@ -79,6 +116,7 @@
[/root]
[client]
client_round = true
border_height = 3
border_shadow = true
border_normal = "#191919"
@@ -106,6 +144,8 @@
[mouse] button = "3" func = "mouse_resize" [/mouse]
[button]
# Available "free", "max", "tile" flags of button.
flags = "free,max,tile"
[mouse] button = "1" func = "client_kill" [/mouse]
[mouse] button = "3" func = "menu" cmd = "clientmenu" [/mouse]
@@ -124,10 +164,14 @@
# place_at_mouse = false
# x = 40 y = 50
# Available "center", "left", "right" menu align. Default: "center".
align = "left"
fg_focus = "#191919" bg_focus = "#7E89A2"
fg_normal = "#9F9AB3" bg_normal = "#191919"
[item] name = "Terminal" func = "spawn" cmd = "@WMFS_TERM@" [/item]
[item] name = "Applications" submenu = "appmenu" [/item]
[item] name = "Next tag" func = "tag_next" [/item]
[item] name = "Previous tag" func = "tag_prev" [/item]
[item] name = "Next layout" func = "layout_next" [/item]
@@ -136,15 +180,27 @@
[item] name = "Quit WMFS" func = "quit" [/item]
[/set_menu]
[set_menu]
name = "appmenu"
align = "left"
fg_focus = "#191919" bg_focus = "#7E89A2"
fg_normal = "#9F9AB3" bg_normal = "#191919"
[item] name = "Browser" func = "spawn" cmd = "firefox" [/item]
[item] name = "Calculator" func = "spawn" cmd = "xcalc" [/item]
[/set_menu]
[set_menu]
name = "clientmenu"
fg_focus = "#D4D4D4" bg_focus = "#003366"
fg_normal = "#D4D4D4" bg_normal = "#191919"
[item] name = "Close" func = "client_kill" [/item]
[item] name = "Maximize" func = "toggle_max" [/item]
[item] name = "Free" func = "toggle_free" [/item]
# Check items: possible 'check_max' or 'check_free'.
[item] name = "Close" func = "client_kill" [/item]
[item] name = "Maximize" func = "toggle_max" check = "check_max" [/item]
[item] name = "Free" func = "toggle_free" check = "check_free" [/item]
[/set_menu]
[/menu]
@@ -194,6 +250,9 @@
# Toggle the resizehint of the current tag/screen
[key] mod = {"Shift", "Control"} key = "r" func = "toggle_resizehint" [/key]
# Toggle the tag_autohide mode
[key] mod = {"Shift", "Control"} key = "t" func = "toggle_tagautohide" [/key]
# Select the next client.
[key] mod = {"Alt"} key = "Tab" func = "client_next" [/key]
@@ -206,6 +265,12 @@
# Select the previous tag.
[key] mod = {"Control"} key = "Left" func = "tag_prev" [/key]
# Select the next visible tag.
[key] mod = {"Control","Alt"} key = "Right" func = "tag_next_visible" [/key]
# Select the previous visible tag.
[key] mod = {"Control","Alt"} key = "Left" func = "tag_prev_visible" [/key]
# Set the next layout.
[key] mod = {"Alt"} key = "space" func = "layout_next" [/key]
@@ -251,6 +316,18 @@
[key] mod = {"Alt", "Shift"} key = "F7" func = "tag_transfert" cmd ="7" [/key]
[key] mod = {"Alt", "Shift"} key = "F8" func = "tag_transfert" cmd ="8" [/key]
[key] mod = {"Alt", "Shift"} key = "F9" func = "tag_transfert" cmd ="9" [/key]
# Toggle additional tags (x) on the current tag
[key] mod = {"Alt", "Super"} key = "F1" func = "tag_toggle_additional" cmd ="1" [/key]
[key] mod = {"Alt", "Super"} key = "F2" func = "tag_toggle_additional" cmd ="2" [/key]
[key] mod = {"Alt", "Super"} key = "F3" func = "tag_toggle_additional" cmd ="3" [/key]
[key] mod = {"Alt", "Super"} key = "F4" func = "tag_toggle_additional" cmd ="4" [/key]
[key] mod = {"Alt", "Super"} key = "F5" func = "tag_toggle_additional" cmd ="5" [/key]
[key] mod = {"Alt", "Super"} key = "F6" func = "tag_toggle_additional" cmd ="6" [/key]
[key] mod = {"Alt", "Super"} key = "F7" func = "tag_toggle_additional" cmd ="7" [/key]
[key] mod = {"Alt", "Super"} key = "F8" func = "tag_toggle_additional" cmd ="8" [/key]
[key] mod = {"Alt", "Super"} key = "F9" func = "tag_toggle_additional" cmd ="9" [/key]
[/keys]