Compare commits

...

232 Commits

Author SHA1 Message Date
Martin Duquesnoy
ecb0f82058 Merge pull request #71 from MicroJoe/master
Added an auto-maximum feature to graphs
2012-08-09 06:02:51 -07:00
Romain Porte
b9d4160273 Random size bug fix 2012-08-07 23:29:22 +02:00
Romain Porte
6f84f0cbbd Added an auto-maximum feature to graphs 2012-08-07 23:11:44 +02:00
Martin Duquesnoy
6e3f6ef326 Merge pull request #66 from MicroJoe/master
Prevent graph from drawing overflow
2012-07-08 10:25:18 -07:00
MicroJoe
29e9cee5fb Prevent graph from drawing overflow 2012-07-07 19:10:37 +02:00
Martin Duquesnoy
6d5ffbe33f Merge pull request #65 from m-r-r/master
Fallback on the system configuration file
2012-07-02 05:34:35 -07:00
m-r-r
289c920fc5 Fallback on the system configuration file 2012-07-02 11:26:06 +02:00
Martin Duquesnoy
67ec2d4c2b Merge pull request #64 from oblique/master
Pull request
2012-06-27 22:43:26 -07:00
oblique
d9d7a40c19 Fix some memory corruptions 2012-06-28 06:40:49 +03:00
Martin Duquesnoy
5b4e656cb1 Merge pull request #63 from Engil/master
Fix NetBSD default search path in configure script
2012-06-25 02:59:14 -07:00
Martin Duquesnoy
83a92da659 Merge pull request #62 from m-r-r/master
Lintian errors removed
2012-06-24 15:45:34 -07:00
m-r-r
37a75dd3aa Added debian-specific flags in ./configure 2012-06-24 16:41:22 +02:00
m-r-r
c8129495b8 New standards version in debian/control (Lintian) 2012-06-24 15:21:46 +02:00
m-r-r
7d05727220 Added a Debian release number debian/changelog (for Lintian) 2012-06-24 15:20:58 +02:00
m-r-r
e4f928fd6e COPYING included in debian/copyright (for Lintian) 2012-06-24 15:16:59 +02:00
Martin Duquesnoy
af8dab2e08 Merge pull request #61 from m-r-r/master
Update of the Debian package
2012-06-24 04:39:54 -07:00
m-r-r
baa3024d25 Update of the Debian package 2012-06-24 13:24:26 +02:00
Martin Duquesnoy
b7b0577aa9 Fix warnings 2012-06-22 19:23:40 +02:00
Martin Duquesnoy
e15c1936ac Same for the event one 2012-06-22 19:09:13 +02:00
Martin Duquesnoy
018176c4ef Replace deprecated X functions XKeycodeToKeysym to XkbKeycodeToKeysym using XKBlib.h 2012-06-22 19:06:47 +02:00
Enguerrand Decorne
7b6ff74311 Fix NetBSD paths in configure script 2012-06-19 00:58:29 +02:00
David Delassus
59af606147 Merge pull request #53 from linkdd/sticky-window
Fix manage of sticky windows (Closes #52)
2012-05-05 06:43:59 -07:00
David Delassus
151dc9f9f1 Fix manage of sticky windows 2012-05-05 15:42:07 +02:00
arnault
67c635f9be add infobar_toggle_hide in wmfsrc & man 2012-05-04 20:48:46 +02:00
Martin Duquesnoy
eed683ca00 Merge pull request #51 from linkdd/sticky-window
Sticky window
2012-05-04 10:57:46 -07:00
David Delassus
643d2a6b26 Manage _NET_WM_STATE_STICKY 2012-05-04 19:37:51 +02:00
David Delassus
8b49878f50 Merge branch 'master' of git://github.com/xorg62/wmfs 2012-05-03 14:28:29 +02:00
David Delassus
10089601c1 Add uicb_infobar_toggle_hide (Closes #18) 2012-05-03 14:25:34 +02:00
arnault
7ee4d47cf8 add autofocus in man & wmfsrc 2012-05-03 14:04:31 +02:00
Martin Duquesnoy
d7adef7bd1 Merge pull request #49 from linkdd/master
focus feature
2012-05-03 04:44:46 -07:00
arnault
86d69595d9 add circular & tabbing in man 2012-05-02 17:08:28 +02:00
David Delassus
9d9460bfc0 Add autofocus option in [client] section 2012-05-02 16:51:15 +02:00
David Delassus
736f98e37f Don't change focused window when creating a new client 2012-05-02 16:39:42 +02:00
David Delassus
9eda6553db Merge pull request #48 from linkdd/master
Fix mistake
2012-05-02 01:58:00 -07:00
David Delassus
d6b97c6c5f Fix little mistake 2012-05-02 10:55:18 +02:00
David Delassus
39cea3ec54 Fix manage of _NET_WINDOW_TYPE_DESKTOP at reload 2012-05-02 10:25:46 +02:00
Martin Duquesnoy
5dc6199cac Merge pull request #47 from linkdd/master
Add padding option
2012-05-02 01:19:18 -07:00
David Delassus
3721ed582e Fix bugs in padding option (Closes #19) 2012-05-02 10:17:25 +02:00
David Delassus
f031d1560c Merge branch 'master' of github.com:linkdd/wmfs 2012-05-02 09:32:37 +02:00
David Delassus
5714d5470b Put W->tag_ciruclar in W->flags as a flag (WMFS_TAGCIRC) ; Add padding option (Closes #19) 2012-05-01 22:10:08 +02:00
Martin Duquesnoy
6e171ffb62 Merge pull request #46 from linkdd/master
Add circular option
2012-05-01 08:03:01 -07:00
David Delassus
eecde8774c Add circular option in section [tags] ; Make user able to turn off the 'tag_prev on first tag send to last tag' effect 2012-05-01 16:58:22 +02:00
arnault
da97ee762c fix man 2012-04-20 17:11:47 +02:00
Martin Duquesnoy
4e2c6125ca Merge pull request #45 from linkdd/master
Manage _NET_WM_WINDOW_TYPE_DESKTOP (Closes #29)
2012-04-17 05:37:22 -07:00
David Delassus
3878e89b99 Clean up code 2012-04-17 14:36:17 +02:00
David Delassus
b44ef3383c Manage _NET_WM_WINDOW_TYPE_DESKTOP 2012-04-17 14:20:21 +02:00
Martin Duquesnoy
70bcf3cd50 Merge pull request #44 from kidanger/ignore_tag
Applique la règle ignore_tag au client
2012-04-15 14:13:56 -07:00
Jérémy Anger
afe7d5d246 Merge branch 'master' of https://github.com/kidanger/wmfs into ignore_tag 2012-04-15 22:57:12 +02:00
Jérémy Anger
8d2f2937a4 fix client ignore_tag rule not beeing applied 2012-04-15 22:55:02 +02:00
Jérémy Anger
356556c51a fix client ignore_tag rule not beeing applied 2012-04-15 22:53:45 +02:00
arnault
fcc8ad77aa add default rule sample in wmfsrc 2012-04-15 22:42:48 +02:00
Jérémy Anger
e799b0115c Merge branch 'master' of https://github.com/xorg62/wmfs 2012-04-15 22:42:09 +02:00
Martin Duquesnoy
7aaae95b6c Merge pull request #41 from kidanger/master
Ajoute la possibilité de créer une règle "par défaut".
2012-04-15 13:32:36 -07:00
Jérémy Anger
17a9d3762f Merge branch 'master' of https://github.com/xorg62/wmfs 2012-04-15 09:34:53 +02:00
arnault
756bb3fbce update man with toggle_ignore_tag uicb function 2012-04-15 02:50:12 +02:00
arnault
ae2756452e add client focus option and client toggle ignore_tag keybind in wmfsrc 2012-04-15 02:44:05 +02:00
Martin Duquesnoy
aae337af8f Merge pull request #42 from kidanger/ignore_tag
Ajout d'un mode pour les clients : ignore_tag
2012-04-14 16:47:18 -07:00
Martin Duquesnoy
ef855ae533 Merge pull request #43 from kidanger/focus
Configuration du comportement de focus
2012-04-14 16:45:40 -07:00
Jérémy Anger
bb952d8c8e better focus configuration : allow "enter click" 2012-04-14 23:05:16 +02:00
Jérémy Anger
e65c6a706a fix client integration on the screen 2012-04-14 22:46:30 +02:00
Jérémy Anger
c692505b44 fix infinite loop 2012-04-14 22:46:10 +02:00
Jérémy Anger
3d450c3d20 fix client moving 2012-04-14 22:46:08 +02:00
Jérémy Anger
0085dd16e3 Add a toggle_ignore_tag uicb command. Don't tab if two client haven't the same ignore_tag rule 2012-04-14 22:45:25 +02:00
Jérémy Anger
9cc33f8904 fix focus on tag change 2012-04-14 22:45:25 +02:00
Jérémy Anger
762700bd2c fix last commit: add wmfs header changes 2012-04-14 22:45:25 +02:00
Jérémy Anger
2abf2ea651 move clients on tag change if they ignore tags 2012-04-14 22:45:16 +02:00
Jérémy Anger
f9624a9f2e add focus configuration 2012-04-14 11:43:51 +02:00
Jérémy Anger
ea517457e4 fix last indentation issue 2012-04-12 15:09:31 +02:00
Jérémy Anger
653d8d9b7b fix indentation 2012-04-12 15:04:24 +02:00
Jérémy Anger
3540bb1cad clean code 2012-04-12 14:52:47 +02:00
Jérémy Anger
4a186874aa fix crash 2012-04-12 13:39:37 +02:00
Jeu2
80eadd6f5c add ability to set a default rule
modified:   src/client.c
	modified:   src/config.c
	modified:   src/wmfs.h
2012-04-12 12:04:57 +02:00
arnault
1c179484b3 fix tag_add/del keybind 2012-03-18 21:26:24 +01:00
Martin Duquesnoy
f0bf12770e Fix strncpy for -C option 2012-03-13 15:01:34 +01:00
Martin Duquesnoy
154571b65b Add dimmer shift in split size of layout split to keep parent at closing 2012-03-09 11:13:43 +01:00
Martin Duquesnoy
d5aed8831b Same for graph 2012-03-08 17:08:01 +01:00
Martin Duquesnoy
e4def827f0 Same for P sequence 2012-03-08 16:54:13 +01:00
Martin Duquesnoy
a6cace77a4 Limit progress/position bar status sequence to max value 2012-03-08 16:39:59 +01:00
Martin Duquesnoy
fe7cf64407 Fix while client_gb_titlebar 2012-03-08 16:28:47 +01:00
Martin Duquesnoy
0d0cb3190a Fix client_gb functions 2012-03-08 15:54:37 +01:00
Martin Duquesnoy
f5f97fc442 Revert "Sel/Normal statusline for client above free statusline"
This reverts commit 63d8f3b4e783c35609f25c1a1690244491a20192.
2012-02-26 20:18:44 +01:00
Martin Duquesnoy
63d8f3b4e7 Sel/Normal statusline for client above free statusline 2012-02-26 14:32:20 +01:00
Martin Duquesnoy
4b5e0aa0da Revert "Sel/Normal statusline for client above free statusline"
This reverts commit 59649248eac9b3b7997f2aebdc209b0fc52d49a8.
2012-02-26 14:12:10 +01:00
Martin Duquesnoy
59649248ea Sel/Normal statusline for client above free statusline 2012-02-26 14:06:21 +01:00
Martin Duquesnoy
8506c8b722 Add client_free_statusline example in default conf 2012-02-26 13:23:01 +01:00
Martin Duquesnoy
6f43efed44 Add feature #28 requested by arpinux: client_free_statusline in theme section 2012-02-26 13:18:00 +01:00
Martin Duquesnoy
0e61b49467 Merge pull request #24 from m-r-r/master
Debian package updated
2012-02-25 08:09:02 -08:00
Martin Duquesnoy
8728e81096 Check for cmd in uicb_launcher 2012-02-21 12:47:54 +01:00
Martin Duquesnoy
980832b474 Use XAllocNamedColor to translate string color 2012-02-21 07:01:35 +01:00
Martin Duquesnoy
04c3b9362e Fix client re-integration at reload when coming from a deleted tag 2012-02-20 00:42:12 +01:00
m-r-r
9434b44819 Last minute correction 2012-02-19 09:58:24 +01:00
m-r-r
639428e132 debian/changelog up to date 2012-02-18 19:42:38 +01:00
m-r-r
76eb77b07f Improved debian/rules script 2012-02-18 19:38:26 +01:00
m-r-r
f225ae4a49 The .desktop file is now installed with the package 2012-02-18 19:31:46 +01:00
m-r-r
c2d355f218 Updated URIs of the debian/watch file 2012-02-18 19:30:27 +01:00
m-r-r
e78a33801f No more VIM addon :-( 2012-02-18 19:26:16 +01:00
m-r-r
bbf16e1797 New man page installed instead of the one generated by help2man 2012-02-18 19:24:54 +01:00
m-r-r
b744ab819a Updated debian/ folder 2012-02-18 19:23:49 +01:00
Martin Duquesnoy
d1e1e4a8b7 Merge pull request #23 from duck/master
Fix to configure for MANPATH
2012-02-15 20:22:50 -08:00
Don Harper
9431660785 configure: added logic to be able to define MANPATH on command line. 2012-02-15 21:42:32 -06:00
Martin Duquesnoy
1a6e1a58a7 Take larger to retile after free mode 2012-02-16 02:06:32 +01:00
Martin Duquesnoy
d059c73d60 Try to integrate in the largest client of the tag before get first 2012-02-15 20:14:45 +01:00
Martin Duquesnoy
8ba39d3960 Fix resize at removing fullscreen state with free clients 2012-02-15 19:47:54 +01:00
Martin Duquesnoy
7dd2bcaec9 Fix hole in layout when removing fullscreen state 2012-02-15 19:24:52 +01:00
Martin Duquesnoy
1ccf09a28a Revert unmap event handling try 2012-02-15 19:17:54 +01:00
Martin Duquesnoy
d6afd65f6f Fix urgent flag of tag when hint appears on current tag & try a new way to handle unmap event 2012-02-15 18:52:05 +01:00
Martin Duquesnoy
35ccda32a4 Merge pull request #16 from hobbestigrou/master
Wmfs.vim
2012-02-14 13:35:10 -08:00
arnault
1bb7b852a1 add tag_client_and_set uicb function in man 2012-02-13 19:33:44 +01:00
Martin Duquesnoy
e52dc25469 Merge pull request #21 from sipi/master
bug: tag_client and tag_set simultaneously
2012-02-13 10:13:44 -08:00
Clément SIPIETER
0325823271 Bug #1: add an uicb function named tag_client_and_move 2012-02-13 17:26:42 +01:00
Martin Duquesnoy
70eeae3135 Choose client theme as default theme in rules 2012-02-13 13:00:32 +01:00
Martin Duquesnoy
7c31faa096 Fix graph datas calloc and SLIST_INSERT_TAIL 2012-02-12 02:12:52 +01:00
Martin Duquesnoy
9d9c097dd3 Fix memory free invalid read errors 2012-02-12 01:24:31 +01:00
Martin Duquesnoy
966fdb2acf Use condition to get _WMFS_FUNCTIOn in event 2012-02-11 22:58:16 +01:00
Martin Duquesnoy
34964da69a Move XMapWindow of client_remove in wmfs_quit 2012-02-11 19:08:14 +01:00
Martin Duquesnoy
6fe9b17e83 Map window at remove only if client has removeall state 2012-02-11 19:39:52 +01:00
Martin Duquesnoy
d3718da15d Fix hole at reload only for tiled client -> fix free client resize at reload 2012-02-11 18:27:36 +01:00
Martin Duquesnoy
c8991c84fb Ungrab button of client window in cremove 2012-02-11 14:47:33 +01:00
Martin Duquesnoy
6d962bbbc3 Try checking wm_state in unmap event 2012-02-11 04:38:54 +01:00
Martin Duquesnoy
79f0b02575 One more condition in unmap event if \o/ 2012-02-11 04:07:56 +01:00
arnault
8e4740854b add condition for client_remove 2012-02-11 00:30:58 +01:00
Martin Duquesnoy
652b31dc0f Add condition in unmap event 2012-02-11 00:35:13 +01:00
Martin Duquesnoy
399fded639 Revert "Remove useless map in client_remove"
This reverts commit 12957b473d987486f1be330fb209dab9f42edc4a.
2012-02-11 00:26:44 +01:00
Martin Duquesnoy
12957b473d Remove useless map in client_remove 2012-02-11 00:21:27 +01:00
Martin Duquesnoy
99d732292f Add _NET_WM_WINDOW_TYPE_DIALOG support 2012-02-10 23:25:49 +01:00
Martin Duquesnoy
4bcd7db1ea Remove XSync in client_remove 2012-02-10 22:26:36 +01:00
Martin Duquesnoy
3b06e2ba8f Fix tag update at tag_client 2012-02-10 19:15:35 +01:00
Hobbestigrou
35209a860c Merge remote-tracking branch 'upstream/master' 2012-02-08 16:38:19 +01:00
Hobbestigrou
783bfd14b0 [Core] Wmfs: Don't need wmfs.vim here. 2012-02-08 16:17:40 +01:00
arnault
24ad1ad813 add status section in manpages 2012-02-08 13:19:33 +01:00
arnault
1b12c23859 add updated manual pages and Makefile.in 2012-02-08 12:27:14 +01:00
arnault
bc4e475a74 fix resize iucb 2012-02-08 00:30:02 +01:00
arnault
4a25ac77e3 dummy fix 2012-02-07 21:07:04 +01:00
arnault
0d8135aacd update keybind_help script - fix align issue 2012-02-07 21:03:50 +01:00
arnault
925c01466a update keybind_help script 2012-02-07 20:06:58 +01:00
arnault
ce693abe89 update keybind_help script 2012-02-07 19:42:44 +01:00
arnault
bf398bd328 update keybind_help script 2012-02-07 19:41:22 +01:00
arnault
560ea5fa33 add keybind_help script 2012-02-07 19:26:48 +01:00
Martin Duquesnoy
21ab9cec9a Use client theme as surface theme 2012-02-07 16:59:41 +01:00
Martin Duquesnoy
229597a532 Remove unused variable 2012-02-07 16:30:15 +01:00
David Delassus
f8c6b9e209 Update tag element at client unmanage 2012-02-07 14:22:19 +01:00
Martin Duquesnoy
b753f7cf48 Add possible x,y arg in status_surface (w,h,#color OR x,y,w,h,#color) 2012-02-06 20:38:26 +01:00
Martin Duquesnoy
c2f108a3ae Arrange surface position with screen edge 2012-02-06 16:15:12 +01:00
Martin Duquesnoy
ff269f01b3 Add clean status_surface. cmd syntax: "w;h;bg <statusline>" 2012-02-06 15:29:48 +01:00
Martin Duquesnoy
b5764dd0a6 Fix fullscreen state toggle 2012-02-06 13:59:27 +01:00
Martin Duquesnoy
c23615271a Block refresh for multi statusline per barwin 2012-02-06 11:40:04 +01:00
Martin Duquesnoy
95c3224ad4 Add statusline option in [tag] 2012-02-06 11:31:29 +01:00
Martin Duquesnoy
5508a565a1 Test W->client in tag_client* uicbs 2012-02-06 09:57:06 +01:00
Martin Duquesnoy
33bcc29e83 revert + default occupied statusline 2012-02-06 02:27:38 +01:00
Martin Duquesnoy
0de4a544a3 Add ^P[] sequence for position bar: ^P[left/right;w;h;tickbord;val;valmax;bg;fg] OR x;y 2012-02-05 18:16:36 +01:00
Martin Duquesnoy
1aad44afc4 progressar sequence is vertical if w < h 2012-02-05 17:48:11 +01:00
Martin Duquesnoy
bb2b3e02bb Fix previous tag toggle on last tag 2012-02-04 21:02:22 +01:00
Martin Duquesnoy
5cd3297e1f Add _NET_ACTIVE_WINDOW update in client_focus() 2012-02-04 18:53:49 +01:00
Martin Duquesnoy
d015dc2904 add _NET_CLIENT_LIST support 2012-02-04 18:27:29 +01:00
Martin Duquesnoy
ce4d9c01a1 Fix graph for 0 value 2012-02-04 18:16:33 +01:00
Martin Duquesnoy
aa480e421c Fix graph lines pos 2012-02-04 05:59:10 +01:00
Martin Duquesnoy
537d8a6a27 Remove border arg of ^g[] sequence 2012-02-04 05:41:44 +01:00
Martin Duquesnoy
eb88702788 Add ^g[] sequence for graph: ^g[left/right;w;h;border;val;valmax;fg;bg;name] or x;y 2012-02-04 05:28:36 +01:00
Martin Duquesnoy
4f42f806e1 Add mousebind to p sequence 2012-02-03 18:39:52 +01:00
Martin Duquesnoy
cf701a43b6 Add \p[] sequence: \p[left/right;w;h;bord;val;valmax;bg;fg] OR x;y 2012-02-03 18:34:31 +01:00
Martin Duquesnoy
73e013266b Fix multi infobar dynamic tagging bug 2012-02-02 18:35:14 +01:00
Martin Duquesnoy
06cca7b413 Avoid prev tag action at tag_screen for last tag 2012-02-02 15:19:57 +01:00
Martin Duquesnoy
a6c235e062 Circular tag_next in tag_del 2012-02-02 13:35:41 +01:00
Martin Duquesnoy
dff9738c24 Fix !name case in tag and add default keybinds 2012-02-02 12:57:43 +01:00
Martin Duquesnoy
65c8c7a5ce Add tag_new & tag_del uicb (Dynamic tagging) 2012-02-02 12:03:54 +01:00
Martin Duquesnoy
688dfb34d2 Add tab rule 2012-02-02 11:15:21 +01:00
Martin Duquesnoy
e484510f52 Add client_tab_next_opened uicb 2012-02-02 10:44:38 +01:00
Martin Duquesnoy
8a527bbc81 Merge pull request #15 from hobbestigrou/master
To manage wmfs with login manager.
2012-02-01 15:11:13 -08:00
Hobbestigrou
0b9c0cb9b8 [Core] Makefile: Install wmfs desktop file in share xsessions. 2012-02-02 00:08:17 +01:00
Hobbestigrou
e30a155ad2 [Core] Wmfs: Add a wmfs desktop file for login manger like gdm. 2012-02-02 00:04:03 +01:00
Martin Duquesnoy
50f0911f10 Fix default status.sh 2012-02-01 14:18:18 +01:00
Martin Duquesnoy
acc66f62ab Fix SIGCHLD signal handling, remove fifo from master 2012-02-01 14:13:19 +01:00
Martin Duquesnoy
5e3c44824d Simplify screen_move_client_prev/next 2012-01-31 21:05:24 +01:00
Martin Duquesnoy
f36d60de45 Fix default status.sh 2012-01-31 18:08:30 +01:00
Martin Duquesnoy
a9b5542513 Avoid cc->title = NULL case using draw_text in frame_update 2012-01-31 14:27:24 +01:00
Martin Duquesnoy
235935f36f Use dirent.h instead of fts.h for launcher completion because of compatibility 2012-01-30 23:14:00 +01:00
Martin Duquesnoy
a37c01c56d Use warnl in launcher.c 2012-01-30 13:24:24 +01:00
Martin Duquesnoy
69b2482684 Can set free = false for normally free client 2012-01-30 11:08:15 +01:00
Martin Duquesnoy
ca4fd18e38 Add launcher completion (adapt philpep FTS based completion, thanks philpep) 2012-01-30 10:42:45 +01:00
Martin Duquesnoy
9c7c3a79e2 Minor fixes 2012-01-30 03:11:51 +01:00
Martin Duquesnoy
783799942d Init f to false in layout_split_integrate 2012-01-29 22:39:09 +01:00
Martin Duquesnoy
3fcc2b844b Fix compilation with clang 2012-01-29 21:05:35 +01:00
Martin Duquesnoy
00c6cfebd2 Fix client covering new bar at reload 2012-01-29 16:42:12 +01:00
Martin Duquesnoy
7777dba930 Add default keybind for layout_integrate function 2012-01-29 16:27:51 +01:00
Martin Duquesnoy
057814d5f5 Add layout_integrate_left/right/top/bottom uicb functions 2012-01-29 16:21:01 +01:00
Martin Duquesnoy
9d76026826 no fac_resize for not tiled client 2012-01-29 06:06:00 +01:00
Martin Duquesnoy
8f52715fe3 Fix client flick at untab when free, split arrange closed with free mode 2012-01-29 05:18:51 +01:00
Martin Duquesnoy
3361a3b8bc Fix configureevent for free mode apps-integrated mouse resize, and simplify some code 2012-01-29 04:59:34 +01:00
Martin Duquesnoy
1b31caac9e Fix client tab with free client and mouse (middle click titlebar) 2012-01-29 04:43:42 +01:00
Martin Duquesnoy
63aaa48957 Fix strdup warning, use ISTRDUP in theme section 2012-01-29 04:37:57 +01:00
Martin Duquesnoy
8749b23250 Choose W->ctheme in client_manage 2012-01-29 04:28:12 +01:00
Martin Duquesnoy
25dec6073c Handle signals TERM, QUIT and CHLD for zombies 2012-01-29 04:24:28 +01:00
Martin Duquesnoy
69391afed8 Add theme option in [client] 2012-01-29 04:11:56 +01:00
Martin Duquesnoy
2bf2011cf1 Init display and W after option in main 2012-01-29 03:52:00 +01:00
Martin Duquesnoy
9048729876 Fix client_gb_titlebar with no titlebar case 2012-01-29 02:59:38 +01:00
Martin Duquesnoy
0f3bc2ed0d Allow client move among screens in free mode 2012-01-29 01:35:41 +01:00
Martin Duquesnoy
31df2361a7 Fix free tag, (m'kay #2) 2012-01-28 23:03:33 +01:00
Martin Duquesnoy
9175f28d1b Fix rules m'kay 2012-01-28 21:49:55 +01:00
Martin Duquesnoy
32f8c69a81 Finalize client free mode with multi-screen, mouse and swap 2012-01-28 21:34:39 +01:00
Martin Duquesnoy
2ac4d8ffd0 Fix some free client issues, add double fork in spawn 2012-01-28 17:10:59 +01:00
Martin Duquesnoy
4deb60dfa6 Merge pull request #13 from m-r-r/master
Added a debian/ folder
2012-01-28 04:37:08 -08:00
m-r-r
9481421476 Added the debian/ folder 2012-01-28 12:46:18 +01:00
Martin Duquesnoy
ff95610727 Fix reversed border refresh 2012-01-28 02:35:38 +01:00
Martin Duquesnoy
e8941ae7b8 Add back -c option to send uicb func throught xprops 2012-01-28 02:27:34 +01:00
Martin Duquesnoy
fd27ce371e Improve free client management 2012-01-28 01:52:40 +01:00
Martin Duquesnoy
6cae9e0465 Fix status check for correct end of sequence 2012-01-27 21:13:18 +01:00
Martin Duquesnoy
409d26bf7b Fix configureevent with free mode, set hinted client as free 2012-01-27 18:45:58 +01:00
Martin Duquesnoy
aa71bf00f9 Allow ']' char in string of \s[] sequences, by adding a \ before 2012-01-27 18:26:18 +01:00
Martin Duquesnoy
2ad1e52051 Work on free client with tabbing behavior 2012-01-27 15:43:53 +01:00
Martin Duquesnoy
86069d0a68 Fix statusline context free 2012-01-27 14:00:29 +01:00
Martin Duquesnoy
02e48d1cd8 Merge pull request #11 from paulfariello/master
Correct alignment of sequence in infobar
2012-01-27 02:45:10 -08:00
Paul Fariello
bdef66c8f7 Correct alignment of sequence in infobar 2012-01-27 10:44:47 +01:00
Martin Duquesnoy
dc377e30bd Replace layout_toggle_free by client_toggle_free, fix re-integration in tiled layout 2012-01-26 20:47:46 +01:00
Martin Duquesnoy
6b349bb4e4 Begin to work on free client 2012-01-26 18:02:47 +01:00
Martin Duquesnoy
7c4e9d8dbc Add key_modifier option in [client] 2012-01-26 03:44:01 +01:00
Martin Duquesnoy
a6aa4edbd7 Add urgent tag support, tags_urgent/fg/bg/statusline in conf 2012-01-26 02:58:19 +01:00
Martin Duquesnoy
233be4dbc1 Free data at the end of launcher_process 2012-01-25 23:15:08 +01:00
Martin Duquesnoy
99bb7e0812 ! NEW LAUNCHER ! Uicb function 'launcher', new [lauchers] section and 'l' infobarelement. See default wmfsrc please 2012-01-25 23:11:15 +01:00
Martin Duquesnoy
0ee606d251 Free screen after clients to set tag/screen in props before quit 2012-01-25 15:30:50 +01:00
Martin Duquesnoy
f7a3ef3b3d Fix wmfs_current_tag recovering 2012-01-25 13:58:04 +01:00
Martin Duquesnoy
4d09fae65b Remove debug puts 2012-01-25 04:04:57 +01:00
Martin Duquesnoy
2eba3ccc64 ! NEW SYSTRAY ! systray element as 'y', element dynamic size 2012-01-25 04:01:59 +01:00
Martin Duquesnoy
f8dedf7231 Add systray functions 2012-01-23 12:15:11 +01:00
Martin Duquesnoy
e0aa3ed034 Prepare code for Systray 2012-01-23 11:28:13 +01:00
Martin Duquesnoy
a74f7c15db Remove useless flags in mousebind struct 2012-01-23 05:32:25 +01:00
Martin Duquesnoy
6f383d74b8 Fix status parsing, allow ^ instead of \ for sequence first char 2012-01-23 04:34:13 +01:00
Martin Duquesnoy
5a9d1f6e13 Add client_*_statusline in theme section, improve status core 2012-01-23 01:59:14 +01:00
Martin Duquesnoy
38f3e3b6b0 Add tags_occupied color in theme and tags_*_statusline to draw status sequences in tags button in according to tag state (normal/selected/occupied) 2012-01-22 22:27:26 +01:00
Martin Duquesnoy
feaa413951 Add status_ctx struct to use status sequences everywhere by using context 2012-01-22 20:11:01 +01:00
Martin Duquesnoy
9d462ac71e Add Imlib2 support: option dependence (use --without-imlib2 at configure). New status sequence: \i[left/right;w;h;/path/img] OR \i[x;y;w;h;/path/img] 2012-01-22 18:11:58 +01:00
Martin Duquesnoy
fbbd9df728 Merge branch 'master' of github.com:xorg62/wmfs 2012-01-22 01:49:43 +01:00
Martin Duquesnoy
97fd008856 Add default mousebind for client (scroll to focus next/prev tab) and minor fix 2012-01-22 01:49:25 +01:00
50 changed files with 4360 additions and 802 deletions

View File

@ -11,13 +11,14 @@ SRCS= \
src/ewmh.c \
src/infobar.c \
src/layout.c \
src/launcher.c \
src/parse_api.c \
src/parse.c \
src/screen.c \
src/tag.c \
src/util.c \
src/fifo.c \
src/status.c \
src/systray.c \
src/mouse.c \
src/log.c \
src/wmfs.c
@ -52,9 +53,13 @@ install: all
install ${PROG} ${DESTDIR}${PREFIX}/bin
@echo installing xsession file to ${DESTDIR}${PREFIX}/share/xsessions
mkdir -p ${DESTDIR}${PREFIX}/share/xsessions
install -m 444 wmfs.desktop ${DESTDIR}${PREFIX}/share/xsessions
@echo installing default config file to ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/
mkdir -p ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/
install -m 444 wmfsrc ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/
@echo installing manual pages to ${DESTDIR}${MANPREFIX}/man1/
mkdir -p ${DESTDIR}${MANPREFIX}/man1/
install -m 644 wmfs.1 ${DESTDIR}${MANPREFIX}/man1/wmfs.1
uninstall:
@echo removing executable file from ${DESTDIR}${PREFIX}/bin
@ -63,6 +68,8 @@ uninstall:
@echo removing config file from ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/
rm -f ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/wmfsrc
rmdir ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/
@echo removing manual pages from ${DESTDIR}${MANPREFIX}/man1
rm -f ${DESTDIR}${MANPREFIX}/man1/wmfs.1
dist:
@echo "Generate wmfs-`date +%Y%m`.tar.gz"

24
configure vendored
View File

@ -14,23 +14,30 @@ while true; do
case "$1" in
--without-xinerama)
USE_XINERAMA=""; shift;;
--without-imlib2)
USE_IMLIB2=""; shift;;
--prefix)
[ -z "$2" ] && echo "Missing argument" && exit 1
PREFIX=$2; shift 2;;
--man-prefix)
[ -z "$2" ] && echo "Missing argument" && exit 1
MANPREFIX=$2; shift 2;;
--xdg-config-dir)
[ -z "$2" ] && echo "Missing argument" && exit 1
XDG_CONFIG_DIR=$2; shift 2;;
--help|-h)
echo "Usage: ./configure [options]
--without-xinerama : compile without xinerama support
--without-imlib2 : compile without imlib2 support
--prefix DIRECTORY : install binary with specified prefix (default $PREFIX)
--man-prefix DIRECTORY : install binary with specified prefix (default $PREFIX)
--xdg-config-dir DIRECTORY : install configuration to specified directory (default $XDG_CONFIG_DIR)"
exit 0;;
*) break;;
esac
done
LIBS="$LIBS $USE_XINERAMA"
LIBS="$LIBS $USE_XINERAMA $USE_IMLIB2"
which pkg-config > /dev/null 2>&1
@ -48,8 +55,8 @@ else
CFLAGS="-I/usr/X11R6/include -I/usr/local/include"
LDFLAGS="-L/usr/X11R6/lib -L/usr/local/lib";;
NetBSD)
CFLAGS="-I/usr/X11R7/include -I/usr/local/include"
LDFLAGS="-L/usr/X11R7/lib -L/usr/local/lib";;
CFLAGS="-I/usr/X11R7/include -I/usr/pkg/include"
LDFLAGS="-L/usr/X11R7/lib -L/usr/pkg/lib";;
Linux)
CFLAGS=""
LDFLAGS=""
@ -62,10 +69,19 @@ else
LDFLAGS="$LDFLAGS -lX11"
[ -n "$USE_XINERAMA" ] && LDFLAGS="$LDFLAGS -lXinerama"
[ -n "$USE_IMLIB2" ] && LDFLAGS="$LDFLAGS -lImlib2"
fi
[ -n "$USE_XINERAMA" ] && CFLAGS="$CFLAGS -DHAVE_XINERAMA"
[ -n "$USE_IMLIB2" ] && CFLAGS="$CFLAGS -DHAVE_IMLIB2"
# Debian hardening options http://wiki.debian.org/Hardening
which dpkg-buildflags > /dev/null 2>&1
if [ $? -eq 0 ];
then
CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 `dpkg-buildflags --get CFLAGS`"
LDFLAGS="$LDFLAGS `dpkg-buildflags --get LDFLAGS`"
fi
cat > Makefile << EOF
PREFIX=$PREFIX

45
debian/changelog vendored Normal file
View File

@ -0,0 +1,45 @@
wmfs (2~beta201206-3) unstable; urgency=low
* No hardening-related Lintiant warnings
-- Mickaël Raybaud-Roig <raybaudroigm@gmail.com> Sun, 24 Jun 2012 16:40:54 +0200
wmfs (2~beta201206-2) unstable; urgency=low
* Fixed some Lintian warnings
* New standards version
-- Mickaël Raybaud-Roig <raybaudroigm@gmail.com> Sun, 24 Jun 2012 15:19:38 +0200
wmfs (2~beta201206-1) unstable; urgency=low
* Updated changelog version
* Added build-depends to the control file
* Updated Vcs-* fields in the control file
-- Mickaël Raybaud-Roig <raybaudroigm@gmail.com> Sun, 24 Jun 2012 13:12:26 +0200
wmfs (2~beta-3) unstable; urgency=low
* Modified build script (debian/rules)
* Modified versions in changelog
* Removed the old manpage
* The configuration is done in override_dh_auto_configure (in debian/rules)
* The .desktop file is installed by dh_install
-- Mickaël Raybaud-Roig <raybaudroigm@gmail.com> Sat, 18 Feb 2012 19:40:09 +0100
wmfs (2~beta-2) unstable; urgency=low
* Added a manpage
* Modified the debian/rules script
* Filled debian/copying
* Added dependencies
-- Mickaël Raybaud-Roig <raybaudroigm@gmail.com> Sat, 28 Jan 2012 12:44:18 +0100
wmfs (2~beta-1) unstable; urgency=low
* Initial release
-- Mickaël Raybaud-Roig <raybaudroigm@gmail.com> Sat, 21 Jan 2012 13:22:37 +0100

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
8

16
debian/control vendored Normal file
View File

@ -0,0 +1,16 @@
Source: wmfs
Section: x11
Priority: extra
Maintainer: Mickaël Raybaud-Roig <raybaudroigm@gmail.com>
Build-Depends: debhelper (>= 8.0.0), libimlib2-dev, libxinerama-dev, libx11-dev
Standards-Version: 3.9.3
Homepage: http://wmfs.info
Vcs-Git: git://github.com/xorg62/wmfs.git
Vcs-Browser: https://github.com/xorg62/wmfs
Package: wmfs
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libxinerama1, libimlib2, libxcb1, libfreetype6
Description: Window Manager From Scratch
WMFS (Window Manager From Scratch) is a lightweight and highly configurable
tiling window manager for X.

54
debian/copyright vendored Normal file
View File

@ -0,0 +1,54 @@
Format: http://dep.debian.net/deps/dep5
Upstream-Name: wmfs
Source: http://wmfs.info
Files: *
Copyright: 2011-2012 Martin Duquesnoy <xorg62@gmail.com>
License: BSD-3-Clauses
Files: debian/*
Copyright: 2012 Mickaël Raybaud-Roig <raybaudroigm@gmail.com>
License: WTFPL-2
License: BSD-3-Clauses
Copyright (c) 1983 The Regents of the University of California.
All rights reserved.
.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. 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.
3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
License: WTFPL-2
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
.
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
.
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
.
0. You just DO WHAT THE FUCK YOU WANT TO.

1
debian/docs vendored Normal file
View File

@ -0,0 +1 @@
README

16
debian/rules vendored Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
export DH_VERBOSE=1
override_dh_auto_configure:
./configure --prefix /usr --xdg-config-dir /etc/xdg --man-prefix /usr/share/man/
%:
dh $@

1
debian/source/format vendored Normal file
View File

@ -0,0 +1 @@
3.0 (quilt)

1
debian/wmfs.install vendored Normal file
View File

@ -0,0 +1 @@
wmfs.desktop /usr/share/xsessions

1
debian/wmfs.manpages vendored Normal file
View File

@ -0,0 +1 @@
wmfs.1

1
debian/wmfs.wm vendored Normal file
View File

@ -0,0 +1 @@
/usr/bin/wmfs

64
scripts/keybind_help.sh Executable file
View File

@ -0,0 +1,64 @@
#! /bin/sh
# simple help script for WMFS2 by arpinux
# default keybinds list
xpos="5"
ypos="5"
width="350"
height="730"
bg="#222222"
fg="#7D7D7D"
l01="^s[80;12;$bg;WMFS² Keybinds Help]"
l03="^s[15;35;$fg;launch terminal:]^s[190;35;$fg;Super + Return]"
l04="^s[15;50;$fg;launch prompt:]^s[190;50;$fg;Super + p]"
l05="^s[15;65;$fg;close client:]^s[190;65;$fg;Super + q]"
l06="^s[15;80;$fg;reload wmfs:]^s[190;80;$fg;Control + Alt + r]"
l07="^s[15;95;$fg;quit wmfs:]^s[190;95;$fg;Control + Alt + q]"
l08="^s[15;115;$fg;next client:]^s[190;115;$fg;Alt + Tab]"
l09="^s[15;130;$fg;prev client:]^s[190;130;$fg;Alt + Shift + Tab]"
l10="^s[15;145;$fg;next tabbed client:]^s[190;145;$fg;Super + Tab]"
l11="^s[15;160;$fg;prev tabbed client:]^s[190;160;$fg;Super + Shift + Tab]"
l12="^s[15;175;$fg;left client:]^s[190;175;$fg;Alt + h]"
l13="^s[15;190;$fg;right client:]^s[190;190;$fg;Alt + l]"
l14="^s[15;205;$fg;top client:]^s[190;205;$fg;Alt + k]"
l15="^s[15;220;$fg;bottom client:]^s[190;220;$fg;Alt + j]"
l16="^s[15;235;$fg;swap client left:]^s[190;235;$fg;Control + Shift + h]"
l17="^s[15;250;$fg;swap client right:]^s[190;250;$fg;Control + Shift + l]"
l18="^s[15;265;$fg;swap client top:]^s[190;265;$fg;Control + Shift + k]"
l19="^s[15;280;$fg;swap client bottom:]^s[190;280;$fg;Control + Shift + j]"
l20="^s[15;295;$fg;tab client left:]^s[190;295;$fg;Alt + Shift + h]"
l21="^s[15;310;$fg;tab client right:]^s[190;310;$fg;Alt + Shift + l]"
l22="^s[15;325;$fg;tab client top:]^s[190;325;$fg;Alt + Shift + k]"
l23="^s[15;340;$fg;tab client bottom:]^s[190;340;$fg;Alt + Shift + j]"
l24="^s[15;355;$fg;untab client:]^s[190;355;$fg;Alt + Shift + u]"
l25="^s[15;375;$fg;increase client on left:]^s[190;375;$fg;Super + h]"
l26="^s[15;390;$fg;decrease client from left:]^s[190;390;$fg;Super + l]"
l27="^s[15;405;$fg;increase client on top:]^s[190;405;$fg;Super + k]"
l28="^s[15;420;$fg;decrease client from top:]^s[190;420;$fg;Super + j]"
l29="^s[15;435;$fg;decrease client from right:]^s[190;435;$fg;Super + Control + h]"
l30="^s[15;450;$fg;increase client on right:]^s[190;450;$fg;Super + Control + l]"
l31="^s[15;465;$fg;decrease client from bottom:]^s[190;465;$fg;Super + Control + k]"
l32="^s[15;480;$fg;increase client to bottom:]^s[190;480;$fg;Super + Control + j]"
l33="^s[15;495;$fg;integrate client to left:]^s[190;495;$fg;Super + Control + Alt + h]"
l34="^s[15;510;$fg;integrate client to right:]^s[190;510;$fg;Super + Control + Alt + l]"
l35="^s[15;525;$fg;integrate client to top:]^s[190;525;$fg;Super + Control + Alt + k]"
l36="^s[15;540;$fg;integrate client to bottom:]^s[190;540;$fg;Super + Control + Alt + j]"
l37="^s[15;560;$fg;horizontal layout:]^s[190;560;$fg;Super + Shift + m]"
l38="^s[15;575;$fg;vertical layout:]^s[190;575;$fg;Super + m]"
l39="^s[15;590;$fg;layout rotate right:]^s[190;590;$fg;Super + r]"
l40="^s[15;605;$fg;layout rotate left:]^s[190;605;$fg;Super + Shift + r]"
l41="^s[15;620;$fg;toggle client free:]^s[190;620;$fg;Super + f]"
l42="^s[15;640;$fg;prev/next tag:]^s[190;640;$fg;Control + Left/Right]"
l43="^s[15;655;$fg;prev/next screen:]^s[190;655;$fg;Control + Up/Down]"
l44="^s[15;670;$fg;set tag (x):]^s[190;670;$fg;Super + F(x)]"
l45="^s[15;685;$fg;tag client with (x):]^s[190;685;$fg;Super + Shift + F(x)]"
l46="^s[15;700;$fg;add tag:]^s[190;700;$fg;Super + Shift + -]"
l47="^s[15;715;$fg;delete tag:]^s[190;715;$fg;Super + -]"
frame="^R[0;0;350;15;$fg] ^R[0;728;350;2;$fg] ^R[0;0;2;730;$fg] ^R[348;0;2;730;$fg]"
wmfs -c status_surface "$xpos,$ypos,$width,$height,$bg $frame $l01 $l03 $l04 $l05 $l06 $l07 $l08 $l09 $l10 $l11 $l12 $l13 $l14 $l15 $l16 $l17 $l18 $l19 $l20 $l21 $l22 $l23 $l24 $l25 $l26 $l27 $l28 $l29 $l30 $l31 $l32 $l33 $l34 $l35 $l36 $l37 $l38 $l39 $l40 $l41 $l42 $l43 $l44 $l45 $l46 $l47"

View File

@ -5,7 +5,9 @@ TIMING=10
statustext()
{
echo "status default `date`" > /tmp/wmfs-$DISPLAY.fifo
# Syntax : status <bar name> <data>
# possible sequences as data: \s[] \R[] \i[]
wmfs -c status "default `date`"
}
while true;

View File

@ -23,7 +23,7 @@ barwin_new(Window parent, int x, int y, int w, int h, Color fg, Color bg, bool e
struct barwin *b = (struct barwin*)xcalloc(1, sizeof(struct barwin));
XSetWindowAttributes at =
{
.override_redirect = True,
.override_redirect = true,
.background_pixmap = ParentRelative,
.event_mask = BARWIN_MASK
};
@ -51,6 +51,7 @@ barwin_new(Window parent, int x, int y, int w, int h, Color fg, Color bg, bool e
b->fg = fg;
SLIST_INIT(&b->mousebinds);
SLIST_INIT(&b->statusmousebinds);
/* Attach */
SLIST_INSERT_HEAD(&W->h.barwin, b, next);

View File

@ -22,9 +22,14 @@
#define barwin_refresh(b) XCopyArea(W->dpy, b->dr, b->win, W->gc, 0, 0, b->geo.w, b->geo.h, 0, 0)
#define barwin_map(b) XMapWindow(W->dpy, b->win);
#define barwin_unmap(b) XUnmapWindow(W->dpy, b->win);
#define barwin_move(b, x, y) XMoveWindow(W->dpy, b->win, x, y);
#define barwin_reparent(b, w) XReparentWindow(W->dpy, b->win, w, 0, 0);
static inline void
barwin_move(struct barwin *b, int x, int y)
{
XMoveWindow(W->dpy, b->win, (b->geo.x = x), (b->geo.y = y));
}
struct barwin* barwin_new(Window parent, int x, int y, int w, int h, Color fg, Color bg, bool entermask);
void barwin_remove(struct barwin *b);
void barwin_resize(struct barwin *b, int w, int h);

View File

@ -9,45 +9,42 @@
#include "config.h"
#include "event.h"
#include "barwin.h"
#include "barwin.h"
#include "draw.h"
#include "screen.h"
#include "mouse.h"
#define CLIENT_MOUSE_MOD Mod1Mask
#define CLIENT_RESIZE_DIR(D) \
void uicb_client_resize_##D(Uicb cmd) \
{ \
void uicb_client_resize_##D(Uicb cmd) \
{ \
if(W->client) \
client_fac_resize(W->client, D, ATOI(cmd)); \
}
}
#define CLIENT_ACTION_DIR(A, D) \
void uicb_client_##A##_##D(Uicb cmd) \
{ \
void uicb_client_##A##_##D(Uicb cmd) \
{ \
(void)cmd; \
struct client *c; \
if(W->client && (c = client_next_with_pos(W->client, D))) \
client_##A(c); \
}
}
#define CLIENT_ACTION_IDIR(A, D) \
void uicb_client_##A##_##D(Uicb cmd) \
{ \
void uicb_client_##A##_##D(Uicb cmd) \
{ \
(void)cmd; \
if(W->client) \
client_##A(W->client, D); \
}
}
#define CLIENT_ACTION_LIST(A, L) \
void uicb_client_##A##_##L(Uicb cmd) \
{ \
void uicb_client_##A##_##L(Uicb cmd) \
{ \
(void)cmd; \
struct client *c; \
if(W->client && (c = client_##L(W->client))) \
client_##A(c); \
}
}
/* uicb_client_resize_dir() */
CLIENT_RESIZE_DIR(Right)
@ -90,7 +87,7 @@ CLIENT_ACTION_LIST(focus, prev_tab)
/** Send a ConfigureRequest event to the struct client
* \param c struct client pointer
*/
inline void
void
client_configure(struct client *c)
{
XConfigureEvent ev =
@ -107,8 +104,8 @@ client_configure(struct client *c)
.override_redirect = 0
};
XSendEvent(W->dpy, c->win, False, StructureNotifyMask, (XEvent *)&ev);
XSync(W->dpy, False);
XSendEvent(W->dpy, c->win, false, StructureNotifyMask, (XEvent *)&ev);
XSync(W->dpy, false);
}
struct client*
@ -116,10 +113,15 @@ client_gb_win(Window w)
{
struct client *c = SLIST_FIRST(&W->h.client);
while(c && c->win != w)
c = SLIST_NEXT(c, next);
while(c)
{
if(c->win == w)
return c;
c = SLIST_NEXT(c, next);
}
return NULL;
}
struct client*
@ -127,25 +129,26 @@ client_gb_frame(Window w)
{
struct client *c = SLIST_FIRST(&W->h.client);
while(c && c->frame != w)
c = SLIST_NEXT(c, next);
while(c)
{
if(c->frame == w)
return c;
c = SLIST_NEXT(c, next);
}
return NULL;
}
struct client*
client_gb_pos(struct tag *t, int x, int y)
{
struct client *c = SLIST_FIRST(&t->clients);
struct client *c;
while(c)
{
FOREACH_NFCLIENT(c, &t->clients, tnext)
if(INAREA(x, y, c->geo))
return c;
c = SLIST_NEXT(c, tnext);
}
return NULL;
}
@ -154,10 +157,18 @@ client_gb_titlebar(Window w)
{
struct client *c = SLIST_FIRST(&W->h.client);
while(c && c->titlebar->win != w)
c = SLIST_NEXT(c, next);
if(!c->titlebar)
return NULL;
while(c)
{
if(c->titlebar->win == w)
return c;
c = SLIST_NEXT(c, next);
}
return NULL;
}
/*
@ -187,38 +198,68 @@ client_next_with_pos(struct client *bc, enum position p)
return c;
}
#define FLAG_SWAP2(f1, f2, m1) \
if((f1 & m1) != (f2 & m1)) \
{ \
f1 ^= m1; \
f2 ^= m1; \
}
#define SWAP_ARRANGE_TAB(C) \
SLIST_FOREACH(c, &C->tag->clients, tnext) \
{ \
if(c->tabmaster == C) \
{ \
c->screen = C->screen; \
if((C->flags & CLIENT_FREE) != (c->flags & CLIENT_FREE)) \
{ \
c->flags ^= CLIENT_FREE; \
c->flags ^= CLIENT_TILED; \
} \
} \
}
void
client_swap2(struct client *c1, struct client *c2)
{
struct client *c;
struct tag *t;
struct geo g;
/* Conflict / errors */
if(c1 == c2 || !c1 || !c2)
return;
/* are swapped geos compatible? */
if(client_winsize(c1, &c2->geo)
|| client_winsize(c2, &c1->geo))
return;
/* Reverse FREE/TILED flags if there are different */
FLAG_SWAP2(c1->flags, c2->flags, CLIENT_FREE);
FLAG_SWAP2(c1->flags, c2->flags, CLIENT_TILED);
if(c1->screen != c2->screen)
swap_ptr((void**)&c1->screen, (void**)&c2->screen);
/*
* Arrange flags for all tabbed client of
* possible c1/c2 tabmaster
*/
if(c1->flags & CLIENT_TABMASTER)
SWAP_ARRANGE_TAB(c1);
if(c2->flags & CLIENT_TABMASTER)
SWAP_ARRANGE_TAB(c2);
if(c1->tag != c2->tag)
{
c1->flags |= CLIENT_IGNORE_LAYOUT;
c2->flags |= CLIENT_IGNORE_LAYOUT;
t = c1->tag;
tag_client(c2->tag, c1);
tag_client(t, c2);
}
c1->tgeo = c2->geo;
c2->tgeo = c1->geo;
g = c1->geo;
client_moveresize(c1, &c2->geo);
client_moveresize(c2, &g);
c1->flags |= CLIENT_IGNORE_ENTER;
c2->flags |= CLIENT_IGNORE_ENTER;
client_moveresize(c1, &c1->tgeo);
client_moveresize(c2, &c2->tgeo);
}
static inline struct client*
@ -263,7 +304,7 @@ client_swap(struct client *c, enum position p)
if(ev.type == KeyPress)
{
XKeyPressedEvent *ke = &ev.xkey;
keysym = XKeycodeToKeysym(W->dpy, (KeyCode)ke->keycode, 0);
keysym = XkbKeycodeToKeysym(W->dpy, (KeyCode)ke->keycode, 0, 0);
_REV_SBORDER();
@ -322,13 +363,13 @@ client_grabbuttons(struct client *c, bool focused)
while(i++ != Button5)
{
XGrabButton(W->dpy, i, CLIENT_MOUSE_MOD, c->win, False,
XGrabButton(W->dpy, i, W->client_mod, c->win, False,
ButtonMask, GrabModeAsync, GrabModeSync, None, None);
XGrabButton(W->dpy, i, CLIENT_MOUSE_MOD | LockMask, c->win, False,
XGrabButton(W->dpy, i, W->client_mod | LockMask, c->win, False,
ButtonMask, GrabModeAsync, GrabModeSync, None, None);
XGrabButton(W->dpy, i, CLIENT_MOUSE_MOD | W->numlockmask, c->win, False,
XGrabButton(W->dpy, i, W->client_mod | W->numlockmask, c->win, False,
ButtonMask, GrabModeAsync, GrabModeSync, None, None);
XGrabButton(W->dpy, i, CLIENT_MOUSE_MOD | LockMask | W->numlockmask, c->win, False,
XGrabButton(W->dpy, i, W->client_mod | LockMask | W->numlockmask, c->win, False,
ButtonMask, GrabModeAsync, GrabModeSync, None, None);
}
@ -346,10 +387,26 @@ client_grabbuttons(struct client *c, bool focused)
#define _REMAINDER() \
if((rm = ((x + f) - (c->rgeo.w - c->border))) > 0) \
f -= rm;
#define _STATUSLINE(C, b) \
do { \
sctx = (b ? &c->theme->client_s_sl : &c->theme->client_n_sl); \
sctx->barwin = C->titlebar; \
status_copy_mousebind(sctx); \
status_render(sctx); \
if(C->flags & CLIENT_FREE) \
{ \
sctx = &c->theme->client_f_sl; \
sctx->barwin = C->titlebar; \
status_copy_mousebind(sctx); \
status_render(sctx); \
} \
} while(/* CONSTCOND */ 0);
void
client_frame_update(struct client *c, struct colpair *cp)
{
struct client *cc;
struct status_ctx *sctx;
int y, f, xt, rm, w, n = 1;
if(c->flags & CLIENT_TABBED)
@ -384,6 +441,9 @@ client_frame_update(struct client *c, struct colpair *cp)
barwin_move(c->titlebar, 0, 0);
barwin_resize(c->titlebar, f, c->tbarw);
barwin_refresh_color(c->titlebar);
_STATUSLINE(c, (cp == &c->scol));
draw_text(c->titlebar->dr, c->theme, xt, y, cp->fg, c->title);
barwin_refresh(c->titlebar);
}
@ -392,10 +452,12 @@ client_frame_update(struct client *c, struct colpair *cp)
{
struct geo g = { f - 1, 0, 1, c->titlebar->geo.h };
int x = c->border;
char *title;
SLIST_FOREACH(cc, &c->tag->clients, tnext)
{
w = (cc->title ? draw_textw(c->theme, cc->title) : 0);
title = (cc->title ? cc->title : "WMFS");
w = draw_textw(c->theme, title);
_XTEXT();
if(cc == c)
@ -407,8 +469,10 @@ client_frame_update(struct client *c, struct colpair *cp)
barwin_resize(c->titlebar, f, c->tbarw);
barwin_refresh_color(c->titlebar);
draw_rect(cc->titlebar->dr, g, c->scol.bg);
draw_text(c->titlebar->dr, c->theme, xt, y, cp->fg, c->title);
_STATUSLINE(c, true);
draw_rect(c->titlebar->dr, &g, c->scol.bg);
draw_text(c->titlebar->dr, c->theme, xt, y, cp->fg, title);
barwin_refresh(c->titlebar);
x += f;
@ -423,8 +487,10 @@ client_frame_update(struct client *c, struct colpair *cp)
barwin_resize(cc->titlebar, f, c->tbarw - 2);
barwin_refresh_color(cc->titlebar);
draw_rect(cc->titlebar->dr, g, c->scol.bg);
draw_text(cc->titlebar->dr, c->theme, xt, y - 1, c->ncol.fg, cc->title);
_STATUSLINE(cc, false);
draw_rect(cc->titlebar->dr, &g, c->scol.bg);
draw_text(cc->titlebar->dr, c->theme, xt, y - 1, c->ncol.fg, title);
barwin_refresh(cc->titlebar);
x += f;
@ -433,7 +499,6 @@ client_frame_update(struct client *c, struct colpair *cp)
}
}
void
client_tab_focus(struct client *c)
{
@ -444,7 +509,9 @@ client_tab_focus(struct client *c)
c->flags |= CLIENT_TABMASTER;
c->flags &= ~CLIENT_TABBED;
client_moveresize(c, &c->tabmaster->geo);
if(c->tag == c->screen->seltag)
client_map(c);
@ -477,9 +544,12 @@ client_tab_focus(struct client *c)
void
_client_tab(struct client *c, struct client *cm)
{
/* Do not tab already tabed client */
Flags m[2] = { CLIENT_TILED, CLIENT_FREE };
/* Do not tab already tabbed client */
if(c->flags & (CLIENT_TABBED | CLIENT_TABMASTER)
|| c->tag != cm->tag || c == cm)
|| c->tag != cm->tag || c == cm
|| !COMPCLIENT(c, cm))
return;
layout_split_arrange_closed(c);
@ -488,6 +558,12 @@ _client_tab(struct client *c, struct client *cm)
c->geo = cm->geo;
cm->tabmaster = c;
if(cm->flags & CLIENT_FREE)
swap_int((int*)&m[0], (int*)&m[1]);
c->flags |= m[0];
c->flags &= ~m[1];
client_focus(cm);
}
@ -512,6 +588,7 @@ client_untab(struct client *c)
{
client_tab_focus(cc);
c->flags &= ~CLIENT_TABBED;
c->flags |= CLIENT_IGNORE_ENTER;
c->tabmaster = NULL;
/* Looking for tabbed client in cc, if there is not
@ -531,7 +608,8 @@ client_untab(struct client *c)
{
c->geo = c->tgeo = og;
layout_split_integrate(c, cc);
c->tag->sel = cc;
layout_client(c);
client_map(c);
client_moveresize(c, &c->geo);
client_update_props(c, CPROP_TAB);
@ -567,7 +645,17 @@ client_focus(struct client *c)
client_grabbuttons(c, true);
client_tab_focus(c);
client_frame_update(c, CCOL(c));
if(c->flags & CLIENT_FREE
&& !(c->flags & (CLIENT_FULLSCREEN | CLIENT_TABBED)))
{
c->tag->flags |= CLIENT_IGNORE_ENTER;
XRaiseWindow(W->dpy, c->frame);
}
XSetInputFocus(W->dpy, c->win, RevertToPointerRoot, CurrentTime);
XChangeProperty(W->dpy, W->root, W->net_atom[net_active_window], XA_WINDOW, 32,
PropModeReplace, (unsigned char *)&c->win, 1);
}
else
{
@ -600,10 +688,10 @@ client_get_name(struct client *c)
unsigned long ir, il;
/* This one instead XFetchName for utf8 name support */
if(XGetWindowProperty(W->dpy, c->win, ATOM("_NET_WM_NAME"), 0, 4096,
False, ATOM("UTF8_STRING"), &rt, &rf, &ir, &il, (unsigned char**)&c->title) != Success)
XGetWindowProperty(W->dpy, c->win, ATOM("WM_NAME"), 0, 4096,
False, ATOM("UTF8_STRING"), &rt, &rf, &ir, &il, (unsigned char**)&c->title);
if(XGetWindowProperty(W->dpy, c->win, W->net_atom[net_wm_name], 0, 65536,
False, W->net_atom[utf8_string], &rt, &rf, &ir, &il, (unsigned char**)&c->title) != Success)
XGetWindowProperty(W->dpy, c->win, W->net_atom[net_wm_name], 0, 65536,
False, W->net_atom[utf8_string], &rt, &rf, &ir, &il, (unsigned char**)&c->title);
/* Still no title... */
if(!c->title)
@ -654,7 +742,7 @@ uicb_client_close(Uicb cmd)
client_close(W->client);
}
static void
void
client_get_sizeh(struct client *c)
{
long msize;
@ -721,6 +809,7 @@ static void
client_frame_new(struct client *c)
{
struct barwin *frameb;
struct barwin *clientb;
XSetWindowAttributes at =
{
.background_pixel = c->ncol.bg,
@ -731,6 +820,7 @@ client_frame_new(struct client *c)
/* Use a fake barwin only to store mousebinds of frame win */
frameb = barwin_new(W->root, 0, 0, 1, 1, 0, 0, false);
clientb = barwin_new(W->root, 0, 0, 1, 1, 0, 0, false);
frameb->win =
c->frame = XCreateWindow(W->dpy, W->root,
@ -741,8 +831,10 @@ client_frame_new(struct client *c)
CopyFromParent,
(CWOverrideRedirect | CWBackPixmap
| CWBackPixel | CWEventMask), &at);
clientb->win = c->win;
frameb->mousebinds = W->tmp_head.client;
clientb->mousebinds = W->tmp_head.client;
if(c->tbarw > c->border)
{
@ -755,6 +847,34 @@ client_frame_new(struct client *c)
XReparentWindow(W->dpy, c->win, c->frame, c->border, c->tbarw);
}
static void
_apply_rule(struct client *c, struct rule *r)
{
if(r->screen != -1)
c->screen = screen_gb_id(r->screen);
c->tag = c->screen->seltag;
if(r->tag != -1)
c->tag = tag_gb_id(c->screen, r->tag);
c->theme = r->theme;
/* free = false for originally free client */
if(r->flags & RULE_FREE)
c->flags |= CLIENT_FREE;
else
c->flags &= ~CLIENT_FREE;
/* Free rule is not compatible with tab rule */
if(r->flags & RULE_TAB)
W->flags ^= WMFS_TABNOC; /* < can be disable by client_tab_next_opened */
if(r->flags & RULE_IGNORE_TAG)
c->flags |= CLIENT_IGNORE_TAG;
c->flags |= CLIENT_RULED;
}
#define RINSTANCE 0x01
#define RCLASS 0x02
#define RROLE 0x04
@ -763,6 +883,7 @@ static void
client_apply_rule(struct client *c)
{
struct rule *r;
struct rule *defaultr = NULL;
char *wmname = NULL;
char *role = NULL;
int f;
@ -783,16 +904,19 @@ client_apply_rule(struct client *c)
}
/* Get _NET_WM_NAME */
if(XGetWindowProperty(W->dpy, c->win, ATOM("_NET_WM_NAME"), 0, 0x77777777, false,
ATOM("UTF8_STRING"), &rf, &f, &n, &il, &data)
if(XGetWindowProperty(W->dpy, c->win, W->net_atom[net_wm_name], 0, 0x77777777, false,
W->net_atom[utf8_string], &rf, &f, &n, &il, &data)
== Success && data)
{
wmname = xstrdup((char*)data);
XFree(data);
}
/* Apply a specific rule */
SLIST_FOREACH(r, &W->h.rule, next)
{
if (r->instance && !strcmp(r->instance, "*"))
defaultr = r;
if(s)
{
FLAGAPPLY(flags, (xch.res_name && r->instance && !strcmp(xch.res_name, r->instance)), RINSTANCE);
@ -803,22 +927,7 @@ client_apply_rule(struct client *c)
FLAGAPPLY(flags, ((role && r->role && !strcmp(role, r->role)) || !role || !r->role), RROLE);
if(flags & (RINSTANCE | RCLASS | RNAME) && flags & RROLE)
{
c->screen = screen_gb_id(r->screen);
c->tag = tag_gb_id(c->screen, r->tag);
c->theme = r->theme;
if(r->flags & RULE_FREE)
{ /* TODO */ }
if(r->flags & RULE_MAX)
{ /* TODO */ }
if(r->flags & RULE_IGNORE_TAG)
{ /* TODO */ }
c->flags = r->flags | CLIENT_RULED;
}
_apply_rule(c, r);
flags = 0;
}
@ -827,6 +936,10 @@ client_apply_rule(struct client *c)
if(wmname)
free(wmname);
/* Apply default rule */
if (!(c->flags & CLIENT_RULED) && defaultr != NULL)
_apply_rule(c, defaultr);
}
struct client*
@ -838,7 +951,7 @@ client_new(Window w, XWindowAttributes *wa, bool scan)
c->win = w;
c->flags = 0;
c->screen = screen_update_sel();
c->theme = THEME_DEFAULT;
c->theme = W->ctheme;
c->tag = NULL;
c->tabmaster = NULL;
@ -850,7 +963,14 @@ client_new(Window w, XWindowAttributes *wa, bool scan)
c->tgeo = c->wgeo = c->rgeo = c->geo;
c->tbgeo = NULL;
client_get_sizeh(c);
if(!scan)
{
if(c->flags & CLIENT_HINT_FLAG /* && OPTIONKIVABIEN */)
c->flags |= CLIENT_FREE;
client_apply_rule(c);
}
/*
* Conf option set per client, for possibility
@ -865,11 +985,11 @@ client_new(Window w, XWindowAttributes *wa, bool scan)
client_frame_new(c);
/* Set tag */
client_get_sizeh(c);
if(!scan)
{
ewmh_manage_window_type(c);
tag_client((c->flags & CLIENT_RULED ? c->tag : c->screen->seltag), c);
}
/* Map, not at reload */
if(c->tag == c->screen->seltag)
@ -883,16 +1003,16 @@ client_new(Window w, XWindowAttributes *wa, bool scan)
/* Attach */
SLIST_INSERT_HEAD(&W->h.client, c, next);
ewmh_set_wm_state(w, NormalState);
if(!scan)
{
client_get_name(c);
if(W->flags & WMFS_AUTOFOCUS)
client_focus(c);
client_configure(c);
ewmh_manage_window_type(c);
}
ewmh_get_client_list();
return c;
}
@ -929,7 +1049,7 @@ client_update_props(struct client *c, Flags f)
}
}
static void
void
client_geo_hints(struct geo *g, int *s)
{
/* base */
@ -965,29 +1085,32 @@ client_geo_hints(struct geo *g, int *s)
g->h = s[MAXH];
}
/* Manage window size in frame in tiling mode */
bool
client_winsize(struct client *c, struct geo *g)
{
int ow, oh;
struct geo og = c->wgeo;
struct geo tmp = *g;
tmp.w -= W->padding >> 1;
tmp.h -= W->padding >> 1;
/* Window geo */
c->wgeo.x = c->border;
c->wgeo.y = c->tbarw;
c->wgeo.h = oh = g->h - (c->border + c->tbarw);
c->wgeo.w = ow = g->w - (c->border << 1);
c->wgeo.h = oh = tmp.h - (c->border + c->tbarw);
c->wgeo.w = ow = tmp.w - (c->border << 1);
client_geo_hints(&c->wgeo, (int*)c->sizeh);
/* Check possible problem for tile integration */
if(ow < c->sizeh[MINW] || oh < c->sizeh[MINH])
{
if(g->w < c->geo.w || g->h < c->geo.h)
if(tmp.w < c->geo.w || tmp.h < c->geo.h)
{
c->wgeo = og;
return true;
}
}
/* Balance position with new size */
c->wgeo.x += (ow - c->wgeo.w) >> 1;
@ -997,30 +1120,69 @@ client_winsize(struct client *c, struct geo *g)
return false;
}
bool
void
client_moveresize(struct client *c, struct geo *g)
{
bool r = true;
if(c->flags & CLIENT_TABBED)
return false;
return;
/* Adjust frame regarding window required size */
if(c->flags & CLIENT_FREE)
{
g->w -= c->border + c->border;
g->h -= c->tbarw + c->border;
client_geo_hints(g, (int*)c->sizeh);
c->wgeo = c->geo = c->rgeo = *g;
c->wgeo.x = c->border;
c->wgeo.y = c->tbarw;
c->geo.w = c->rgeo.w = c->wgeo.w + c->border + c->border;
c->geo.h = c->rgeo.h = c->wgeo.h + c->tbarw + c->border;
c->rgeo.x += c->screen->ugeo.x;
c->rgeo.y += c->screen->ugeo.y;
if(!INAREA(c->rgeo.x, c->rgeo.y, c->screen->ugeo))
{
/* New screen (moved by mouse) */
if(c->flags & CLIENT_MOUSE)
{
c->flags |= CLIENT_IGNORE_LAYOUT;
c->screen = screen_gb_geo(c->rgeo.x, c->rgeo.y);
tag_client(c->screen->seltag, c);
c->geo.x = c->rgeo.x - c->screen->ugeo.x;
c->geo.y = c->rgeo.y - c->screen->ugeo.y;
}
/* Out of the screen case */
else
{
c->geo.x = (c->screen->ugeo.w >> 1) - (c->geo.w >> 1);
c->geo.y = (c->screen->ugeo.h >> 1) - (c->geo.h >> 1);
c->rgeo.x = c->screen->ugeo.x + c->geo.x;
c->rgeo.y = c->screen->ugeo.y + c->geo.y;
}
}
}
/* Adjust window regarding required size for frame (tiling) */
else
{
c->ttgeo = c->tgeo = c->rgeo = c->geo = *g;
if(!(c->flags & CLIENT_DID_WINSIZE))
if(client_winsize(c, g))
{
r = false;
/* TODO
* Window required size not compatible
* with frame window size in tile mode
*/
}
client_winsize(c, g);
/* Real geo regarding full root size */
c->rgeo.x += c->screen->ugeo.x;
c->rgeo.y += c->screen->ugeo.y;
c->rgeo.x += W->padding >> 2;
c->rgeo.y += W->padding >> 2;
c->rgeo.w -= W->padding >> 1;
c->rgeo.h -= W->padding >> 1;
}
XMoveResizeWindow(W->dpy, c->frame,
c->rgeo.x, c->rgeo.y,
c->rgeo.w, c->rgeo.h);
@ -1035,8 +1197,25 @@ client_moveresize(struct client *c, struct geo *g)
client_frame_update(c, CCOL(c));
client_update_props(c, CPROP_GEO);
client_configure(c);
}
return r;
void
client_place_at_mouse(struct client *c)
{
int x, y;
Window w;
int d, u;
XQueryPointer(W->dpy, W->root, &w, &w, &x, &y, &d, &d, (uint *)&u);
if(x < c->screen->ugeo.x)
x = 0;
if(y < c->screen->ugeo.y)
y = 0;
c->geo.x = ((x + c->geo.w) > c->screen->ugeo.w ? c->screen->ugeo.w - c->geo.w : x);
c->geo.y = ((y + c->geo.h) > c->screen->ugeo.h ? c->screen->ugeo.h - c->geo.h : y);
}
void
@ -1083,7 +1262,7 @@ _fac_arrange_row(struct client *c, enum position p, int fac)
struct client *cc;
/* Travel clients to search row parents and apply fac */
SLIST_FOREACH(cc, &c->tag->clients, tnext)
FOREACH_NFCLIENT(cc, &c->tag->clients, tnext)
if(GEO_PARENTROW(g, cc->tgeo, p))
_fac_apply(cc, p, fac);
}
@ -1099,7 +1278,7 @@ _fac_check_to_reverse(struct client *c)
* resize client because of possible error with next
* clients in linked list.
*/
SLIST_FOREACH(gc, &c->tag->clients, tnext)
FOREACH_NFCLIENT(gc, &c->tag->clients, tnext)
if(gc->flags & CLIENT_FAC_APPLIED
&& client_winsize(gc, &gc->tgeo))
{
@ -1107,7 +1286,7 @@ _fac_check_to_reverse(struct client *c)
* Reverse back the flag and the window geo
* in previous affected clients
*/
SLIST_FOREACH(cc, &c->tag->clients, tnext)
FOREACH_NFCLIENT(cc, &c->tag->clients, tnext)
{
cc->tgeo = cc->ttgeo;
cc->flags &= ~CLIENT_DID_WINSIZE;
@ -1123,10 +1302,10 @@ _fac_resize(struct client *c, enum position p, int fac)
struct client *cc, *gc = client_next_with_pos(c, p);
enum position rp = RPOS(p);
if(!gc || gc->screen != c->screen)
if(!gc || gc->screen != c->screen || !(c->flags & CLIENT_TILED))
return;
SLIST_FOREACH(cc, &c->tag->clients, tnext)
FOREACH_NFCLIENT(cc, &c->tag->clients, tnext)
cc->ttgeo = cc->tgeo;
if(GEO_CHECK2(c->tgeo, gc->tgeo, p))
@ -1148,7 +1327,7 @@ client_apply_tgeo(struct tag *t)
{
struct client *c;
SLIST_FOREACH(c, &t->clients, tnext)
FOREACH_NFCLIENT(c, &t->clients, tnext)
{
client_moveresize(c, &c->tgeo);
c->flags &= ~CLIENT_FAC_APPLIED;
@ -1157,7 +1336,7 @@ client_apply_tgeo(struct tag *t)
#define _REV_BORDER() \
do { \
SLIST_FOREACH(gc, &c->tag->clients, tnext) \
FOREACH_NFCLIENT(gc, &c->tag->clients, tnext) \
draw_reversed_rect(W->root, gc, true); \
} while(/* CONSTCOND */ 0);
void
@ -1189,7 +1368,7 @@ client_fac_resize(struct client *c, enum position p, int fac)
if(ev.type == KeyPress)
{
XKeyPressedEvent *ke = &ev.xkey;
keysym = XKeycodeToKeysym(W->dpy, (KeyCode)ke->keycode, 0);
keysym = XkbKeycodeToKeysym(W->dpy, (KeyCode)ke->keycode, 0, 0);
_REV_BORDER();
@ -1240,7 +1419,7 @@ client_fac_resize(struct client *c, enum position p, int fac)
/* Aborted with escape, Set back original geos */
else
{
SLIST_FOREACH(gc, &c->tag->clients, tnext)
FOREACH_NFCLIENT(gc, &c->tag->clients, tnext)
{
gc->tgeo = gc->geo;
gc->flags &= ~CLIENT_DID_WINSIZE;
@ -1251,7 +1430,7 @@ client_fac_resize(struct client *c, enum position p, int fac)
XUngrabKeyboard(W->dpy, CurrentTime);
}
inline void
void
client_fac_hint(struct client *c)
{
int w = c->sizeh[MINW] + c->border + c->border;
@ -1275,31 +1454,76 @@ client_remove(struct client *c)
{
c->flags |= CLIENT_DYING;
XGrabServer(W->dpy);
XSetErrorHandler(wmfs_error_handler_dummy);
client_map(c);
XReparentWindow(W->dpy, c->win, W->root, c->rgeo.x, c->rgeo.y);
client_untab(c);
XDestroyWindow(W->dpy, c->frame);
XGrabServer(W->dpy);
XSetErrorHandler(wmfs_error_handler_dummy);
XReparentWindow(W->dpy, c->win, W->root, c->rgeo.x, c->rgeo.y);
XUngrabButton(W->dpy, AnyButton, AnyModifier, c->win);
ewmh_set_wm_state(c->win, WithdrawnState);
XSync(W->dpy, false);
XSetErrorHandler(wmfs_error_handler);
XUngrabServer(W->dpy);
if(c->titlebar)
barwin_remove(c->titlebar);
/* Remove from global client list */
SLIST_REMOVE(&W->h.client, c, client, next);
tag_client(NULL, c);
ewmh_set_wm_state(c->win, WithdrawnState);
XUngrabServer(W->dpy);
XSync(W->dpy, False);
XSetErrorHandler(wmfs_error_handler);
/* Remove frame */
if(c->titlebar)
barwin_remove(c->titlebar);
XDestroyWindow(W->dpy, c->frame);
free(c);
ewmh_get_client_list();
}
void
uicb_client_toggle_free(Uicb cmd)
{
struct client *c;
(void)cmd;
if(!(W->client))
return;
W->client->flags ^= CLIENT_FREE;
layout_client(W->client);
/* Set tabbed client of toggled client as free */
if(W->client->flags & CLIENT_TABMASTER)
{
SLIST_FOREACH(c, &W->client->tag->clients, tnext)
if(c->tabmaster == W->client && c != W->client)
c->flags ^= CLIENT_FREE;
}
}
void uicb_client_toggle_ignore_tag(Uicb cmd)
{
struct client *c;
(void)cmd;
if(!(W->client))
return;
W->client->flags ^= CLIENT_IGNORE_TAG;
/* Set tabbed client of toggled client as ignore_tag */
if(W->client->flags & CLIENT_TABMASTER)
{
SLIST_FOREACH(c, &W->client->tag->clients, tnext)
if(c->tabmaster == W->client && c != W->client)
c->flags ^= CLIENT_IGNORE_TAG;
}
}
void
uicb_client_tab_next_opened(Uicb cmd)
{
(void)cmd;
W->flags ^= WMFS_TABNOC;
}
void

View File

@ -6,6 +6,8 @@
#ifndef CLIENT_H
#define CLIENT_H
#include <X11/XKBlib.h>
#include "wmfs.h"
#include "layout.h"
#include "ewmh.h"
@ -13,7 +15,15 @@
#define TCLIENT_CHECK(C) (C->flags & CLIENT_TABBED && !(C->flags & CLIENT_TABMASTER))
inline void client_configure(struct client *c);
/* SLIST_FOREACH for client with no free client */
#define FOREACH_NFCLIENT(V, H, F) \
SLIST_FOREACH(V, H, F) \
if(!(V->flags & CLIENT_FREE))
/* Are two clients compatibles ? (to be tabbed together) */
#define COMPCLIENT(C1, C2) ((C1->flags & CLIENT_IGNORE_TAG) == (C2->flags & CLIENT_IGNORE_TAG))
void client_configure(struct client *c);
struct client *client_gb_win(Window w);
struct client *client_gb_frame(Window w);
struct client *client_gb_pos(struct tag *t, int x, int y);
@ -32,8 +42,11 @@ void client_get_name(struct client *c);
void client_close(struct client *c);
void uicb_client_close(Uicb cmd);
struct client *client_new(Window w, XWindowAttributes *wa, bool scan);
void client_geo_hints(struct geo *g, int *s);
void client_get_sizeh(struct client *c);
bool client_winsize(struct client *c, struct geo *geo);
bool client_moveresize(struct client *c, struct geo *g);
void client_moveresize(struct client *c, struct geo *g);
void client_place_at_mouse(struct client *c);
void client_maximize(struct client *c);
void client_fac_resize(struct client *c, enum position p, int fac);
void client_fac_adjust(struct client *c);
@ -48,8 +61,11 @@ void client_apply_tgeo(struct tag *t);
#define CPROP_TAB 0x08
void client_update_props(struct client *c, Flags f);
inline void client_fac_hint(struct client *c);
void client_fac_hint(struct client *c);
void uicb_client_untab(Uicb cmd);
void uicb_client_toggle_free(Uicb cmd);
void uicb_client_toggle_ignore_tag(Uicb cmd);
void uicb_client_tab_next_opened(Uicb cmd);
/* Generated */
void uicb_client_resize_Right(Uicb);
@ -177,5 +193,25 @@ clients_tag_arrange_map(struct tag *t)
sfunc(c);
}
static inline struct client*
client_get_larger(struct tag *t, bool ignoring_tag)
{
struct client *c, *lc = NULL;
int tmp, l = 0;
FOREACH_NFCLIENT(c, &t->clients, tnext)
{
if((tmp = (c->geo.w + c->geo.h)) > l && (c->flags & CLIENT_IGNORE_TAG) == ignoring_tag)
{
l = tmp;
lc = c;
}
}
if(lc && (lc->flags & CLIENT_TABBED))
lc = lc->tabmaster;
return lc;
}
#endif /* CLIENT_H */

View File

@ -10,6 +10,13 @@
#include "screen.h"
#include "infobar.h"
#include "util.h"
#include "status.h"
#define ISTRDUP(t, s) \
do { \
if((tmp = s)) \
t = xstrdup(tmp); \
} while(/* CONSTCOND */ 0);
static void
config_mouse_section(struct mbhead *mousebinds, struct conf_sec **sec)
@ -43,6 +50,7 @@ config_theme(void)
struct theme *t, *p = NULL;
size_t i, n;
struct conf_sec *sec, **ks;
char *tmp;
/* [themes] */
sec = fetch_section_first(NULL, "themes");
@ -75,9 +83,33 @@ config_theme(void)
t->tags_n.bg = color_atoh(fetch_opt_first(ks[i], "#222222", "tags_normal_bg").str);
t->tags_s.fg = color_atoh(fetch_opt_first(ks[i], "#222222", "tags_sel_fg").str);
t->tags_s.bg = color_atoh(fetch_opt_first(ks[i], "#CCCCCC", "tags_sel_bg").str);
t->tags_o.fg = color_atoh(fetch_opt_first(ks[i], "#CCCCCC", "tags_occupied_fg").str);
t->tags_o.bg = color_atoh(fetch_opt_first(ks[i], "#444444", "tags_occupied_bg").str);
t->tags_u.fg = color_atoh(fetch_opt_first(ks[i], "#444444", "tags_urgent_fg").str);
t->tags_u.bg = color_atoh(fetch_opt_first(ks[i], "#CC4444", "tags_urgent_bg").str);
t->tags_border_col = color_atoh(fetch_opt_first(ks[i], "#888888", "tags_border_color").str);
t->tags_border_width = fetch_opt_first(ks[i], "0", "tags_border_width").num;
/* status line */
t->tags_n_sl = status_new_ctx(NULL, t);
t->tags_s_sl = status_new_ctx(NULL, t);
t->tags_o_sl = status_new_ctx(NULL, t);
t->tags_u_sl = status_new_ctx(NULL, t);
ISTRDUP(t->tags_n_sl.status, fetch_opt_first(ks[i], "", "tags_normal_statusline").str);
ISTRDUP(t->tags_s_sl.status, fetch_opt_first(ks[i], "", "tags_sel_statusline").str);
ISTRDUP(t->tags_o_sl.status, fetch_opt_first(ks[i], "", "tags_occupied_statusline").str);
ISTRDUP(t->tags_u_sl.status, fetch_opt_first(ks[i], "", "tags_urgent_statusline").str);
if(t->tags_n_sl.status)
status_parse(&t->tags_n_sl);
if(t->tags_s_sl.status)
status_parse(&t->tags_s_sl);
if(t->tags_o_sl.status)
status_parse(&t->tags_o_sl);
if(t->tags_u_sl.status)
status_parse(&t->tags_u_sl);
/* Client / frame */
t->client_n.fg = color_atoh(fetch_opt_first(ks[i], "#CCCCCC", "client_normal_fg").str);
t->client_n.bg = color_atoh(fetch_opt_first(ks[i], "#222222", "client_normal_bg").str);
@ -87,6 +119,22 @@ config_theme(void)
t->client_titlebar_width = fetch_opt_first(ks[i], "12", "client_titlebar_width").num;
t->client_border_width = fetch_opt_first(ks[i], "1", "client_border_width").num;
/* status line */
t->client_n_sl = status_new_ctx(NULL, t);
t->client_s_sl = status_new_ctx(NULL, t);
t->client_f_sl = status_new_ctx(NULL, t);
ISTRDUP(t->client_n_sl.status, fetch_opt_first(ks[i], "", "client_normal_statusline").str);
ISTRDUP(t->client_s_sl.status, fetch_opt_first(ks[i], "", "client_sel_statusline").str);
ISTRDUP(t->client_f_sl.status, fetch_opt_first(ks[i], "", "client_free_statusline").str);
if(t->client_n_sl.status)
status_parse(&t->client_n_sl);
if(t->client_s_sl.status)
status_parse(&t->client_s_sl);
if(t->client_f_sl.status)
status_parse(&t->client_f_sl);
SLIST_INSERT_TAIL(&W->h.theme, t, next, p);
p = t;
@ -133,9 +181,10 @@ static void
config_tag(void)
{
struct screen *s;
struct tag *t;
size_t i, n;
struct conf_sec *sec, **ks, **mb;
char *name;
char *name, *tmp;
int screenid;
/* [tags] */
@ -143,6 +192,9 @@ config_tag(void)
ks = fetch_section(sec, "tag");
n = fetch_section_count(ks);
if (fetch_opt_first(sec, "1", "circular").boolean)
W->flags |= WMFS_TAGCIRC;
/* [mouse] */
if((mb = fetch_section(sec, "mouse")))
{
@ -158,7 +210,14 @@ config_tag(void)
SLIST_FOREACH(s, &W->h.screen, next)
if(screenid == s->id || screenid == -1)
tag_new(s, name);
{
t = tag_new(s, name);
t->statusctx = status_new_ctx(NULL, NULL);
ISTRDUP(t->statusctx.status, fetch_opt_first(ks[i], "", "statusline").str);
if(t->statusctx.status)
status_parse(&t->statusctx);
}
}
/* If no tag at all on a screen, add one anyway */
@ -173,10 +232,29 @@ static void
config_client(void)
{
struct conf_sec *sec, **mb;
char *tmp;
/* [client] */
sec = fetch_section_first(NULL, "client");
W->padding = fetch_opt_first(sec, "0", "padding").num;
W->client_mod = modkey_keysym(fetch_opt_first(sec, "Super", "key_modifier").str);
if(fetch_opt_first(sec, "0", "autofocus").boolean)
W->flags |= WMFS_AUTOFOCUS;
/* Get theme */
tmp = fetch_opt_first(sec, "default", "theme").str;
W->ctheme = name_to_theme(tmp);
/* Get focus configuration */
W->cfocus = 0;
tmp = fetch_opt_first(sec, "enter", "focus").str;
if(strstr(tmp, "enter"))
W->cfocus |= CFOCUS_ENTER;
if(strstr(tmp, "click"))
W->cfocus |= CFOCUS_CLICK;
/* [mouse] */
/* for client frame AND titlebar */
if((mb = fetch_section(sec, "mouse")))
@ -186,18 +264,12 @@ config_client(void)
}
}
#define ISTRDUP(t, s) \
do { \
if((tmp = s)) \
t = xstrdup(tmp); \
} while(/* CONSTCOND */ 0);
static void
config_rule(void)
{
int i, n;
struct conf_sec *sec, **ks;
struct rule *r;
struct theme *t;
char *tn, *tmp;
/* [rules] */
@ -221,20 +293,13 @@ config_rule(void)
r->tag = fetch_opt_first(ks[i], "-1", "tag").num;
FLAGAPPLY(r->flags, fetch_opt_first(ks[i], "false", "free").boolean, RULE_FREE);
FLAGAPPLY(r->flags, fetch_opt_first(ks[i], "false", "max").boolean, RULE_MAX);
FLAGAPPLY(r->flags, fetch_opt_first(ks[i], "false", "tab").boolean, RULE_TAB);
FLAGAPPLY(r->flags, fetch_opt_first(ks[i], "false", "ignore_tag").boolean, RULE_IGNORE_TAG);
if((tn = fetch_opt_first(ks[i], "", "theme").str))
{
SLIST_FOREACH(t, &W->h.theme, next)
if(!strcmp(tn, t->name))
{
r->theme = t;
break;
}
}
r->theme = name_to_theme(tn);
else
r->theme = SLIST_FIRST(&W->h.theme);
r->theme = W->ctheme;
SLIST_INSERT_HEAD(&W->h.rule, r, next);
}
@ -242,6 +307,38 @@ config_rule(void)
free(ks);
}
static void
config_launcher(void)
{
struct conf_sec *sec, **ks;
struct launcher *l;
int n, i;
/* [launchers] */
sec = fetch_section_first(NULL, "launchers");
ks = fetch_section(sec, "launcher");
n = fetch_section_count(ks);
SLIST_INIT(&W->h.launcher);
/* [launcher] */
for(i = 0; i < n; ++i)
{
l = xcalloc(1, sizeof(struct launcher));
l->name = xstrdup(fetch_opt_first(ks[i], "default", "name").str);
l->prompt = xstrdup(fetch_opt_first(ks[i], ":", "prompt").str);
l->command = xstrdup(fetch_opt_first(ks[i], "spawn", "command").str);
if((l->width = fetch_opt_first(ks[i], "150", "width").num) <= 0)
l->width = 150;
SLIST_INSERT_HEAD(&W->h.launcher, l, next);
}
free(ks);
}
static void
config_keybind(void)
{
@ -304,7 +401,13 @@ config_init(void)
sprintf(W->confpath, "%s/"CONFIG_DEFAULT_PATH, getenv("HOME"));
if(get_conf(W->confpath) == -1)
errxl(1, "parsing default configuration file (%s) failed.", W->confpath);
{
warnxl("parsing default configuration file (%s) failed.", W->confpath);
sprintf(W->confpath, "%s/wmfs/wmfsrc", XDG_CONFIG_DIR);
if(get_conf(W->confpath) == -1)
errxl(1, "parsing system configuration file (%s) failed.", W->confpath);
}
}
config_theme();
@ -313,6 +416,7 @@ config_init(void)
config_client();
config_bars();
config_rule();
config_launcher();
free_conf();
}

View File

@ -17,6 +17,8 @@
#include "status.h"
#include "mouse.h"
#include "screen.h"
#include "infobar.h"
#include "launcher.h"
#define THEME_DEFAULT (SLIST_FIRST(&W->h.theme))
@ -33,9 +35,12 @@ static const struct { char *name; void (*func)(Uicb cmd); } uicb_list[] =
{ "tag_next", uicb_tag_next },
{ "tag_prev", uicb_tag_prev },
{ "tag_client", uicb_tag_client },
{ "tag_client_and_set", uicb_tag_client_and_set },
{ "tag_move_client_next", uicb_tag_move_client_next },
{ "tag_move_client_prev", uicb_tag_move_client_prev },
{ "tag_click", uicb_tag_click },
{ "tag_new", uicb_tag_new },
{ "tag_del", uicb_tag_del },
/* Layout */
{ "layout_vmirror", uicb_layout_vmirror },
@ -44,6 +49,10 @@ static const struct { char *name; void (*func)(Uicb cmd); } uicb_list[] =
{ "layout_rotate_right", uicb_layout_rotate_right },
{ "layout_prev_set", uicb_layout_prev_set },
{ "layout_next_set", uicb_layout_next_set },
{ "layout_integrate_left", uicb_layout_integrate_Left },
{ "layout_integrate_right", uicb_layout_integrate_Right },
{ "layout_integrate_top", uicb_layout_integrate_Top },
{ "layout_integrate_bottom", uicb_layout_integrate_Bottom },
/* Client */
{ "client_close", uicb_client_close },
@ -71,9 +80,16 @@ static const struct { char *name; void (*func)(Uicb cmd); } uicb_list[] =
{ "client_focus_next_tab", uicb_client_focus_next_tab },
{ "client_focus_prev_tab", uicb_client_focus_prev_tab },
{ "client_focus_click", uicb_client_focus_click },
{ "client_toggle_free", uicb_client_toggle_free },
{ "client_toggle_ignore_tag", uicb_client_toggle_ignore_tag },
{ "client_tab_next_opened", uicb_client_tab_next_opened },
/* Status */
{ "status" , uicb_status },
{ "status_surface", uicb_status_surface },
/* Infobar */
{ "infobar_toggle_hide", uicb_infobar_toggle_hide },
/* Mouse */
{ "mouse_resize", uicb_mouse_resize },
@ -87,6 +103,9 @@ static const struct { char *name; void (*func)(Uicb cmd); } uicb_list[] =
{ "screen_move_client_next", uicb_screen_move_client_next },
{ "screen_move_client_prev", uicb_screen_move_client_prev },
/* Launcher */
{ "launcher", uicb_launcher },
{ NULL, NULL }
};

View File

@ -10,6 +10,10 @@
#include <string.h>
#include <X11/Xlib.h>
#ifdef HAVE_IMLIB2
#include <Imlib2.h>
#endif /* HAVE_IMLIB2 */
#include "wmfs.h"
#include "config.h"
#include "screen.h"
@ -25,12 +29,43 @@ draw_text(Drawable d, struct theme *t, int x, int y, Color fg, const char *str)
}
static inline void
draw_rect(Drawable d, struct geo g, Color bg)
draw_rect(Drawable d, struct geo *g, Color bg)
{
XSetForeground(W->dpy, W->gc, bg);
XFillRectangle(W->dpy, d, W->gc, g.x, g.y, g.w, g.h);
XFillRectangle(W->dpy, d, W->gc, g->x, g->y, g->w, g->h);
}
#ifdef HAVE_IMLIB2
/*
* Draw image on drawable with g geo
* Require that the image was loaded with draw_image_load()
*/
static inline void
draw_image(Drawable d, struct geo *g)
{
imlib_context_set_drawable(d);
imlib_render_image_on_drawable_at_size(g->x, g->y, g->w, g->h);
imlib_free_image();
}
/*
* Load image, set it in imlib context, and return
* width & height as argument 2 & 3
*/
static inline void
draw_image_load(char *path, int *w, int *h)
{
Imlib_Image image = imlib_load_image(path);
imlib_context_set_image(image);
*w = imlib_image_get_width();
*h = imlib_image_get_height();
}
#endif /* HAVE_IMLIB2 */
/*
* For client use
*/
@ -41,24 +76,28 @@ draw_reversed_rect(Drawable dr, struct client *c, bool t)
struct geo *ug = &c->screen->ugeo;
int i = c->theme->client_border_width;
if(c->flags & CLIENT_FREE)
{
XDrawRectangle(W->dpy, dr, W->rgc,
ug->x + g->x + i,
ug->y + g->y + i,
g->w - (i << 1),
g->h - (i << 1));
}
else
{
XDrawRectangle(W->dpy, dr, W->rgc,
ug->x + g->x + i + (W->padding >> 2),
ug->y + g->y + i + (W->padding >> 2),
g->w - (i << 1) - (W->padding >> 1),
g->h - (i << 1) - (W->padding >> 1));
}
}
static inline void
draw_reversed_cross(Drawable dr, struct geo *g)
draw_line(Drawable d, int x1, int y1, int x2, int y2)
{
int x = g->x + W->screen->ugeo.x;
int y = g->y + W->screen->ugeo.y;
XDrawLine(W->dpy, dr, W->rgc,
x, y, x + g->w, y + g->h);
XDrawLine(W->dpy, dr, W->rgc,
x + g->w, y, x, y + g->h);
XDrawLine(W->dpy, d, W->gc, x1, y1, x2, y2);
}
static inline unsigned short

View File

@ -5,22 +5,32 @@
#include "event.h"
#include "ewmh.h"
#include "config.h"
#include "util.h"
#include "wmfs.h"
#include "client.h"
#include "barwin.h"
#include "screen.h"
#include "systray.h"
#include "infobar.h"
#define EVDPY(e) (e)->xany.display
#define MOUSE_DO_BIND(m) \
if(m->button == ev->button) \
if(!m->use_area || (m->use_area && INAREA(ev->x, ev->y, m->area))) \
if(m->func) \
m->func(m->cmd);
static void
event_buttonpress(XEvent *e)
{
XButtonEvent *ev = &e->xbutton;
struct mousebind *m;
struct barwin *b;
struct client *c;
screen_update_sel();
status_flush_surface();
SLIST_FOREACH(b, &W->h.barwin, next)
if(b->win == ev->window)
@ -28,13 +38,16 @@ event_buttonpress(XEvent *e)
W->last_clicked_barwin = b;
SLIST_FOREACH(m, &b->mousebinds, next)
if(m->button == ev->button)
if(!m->use_area || (m->use_area && INAREA(ev->x, ev->y, m->area)))
if(m->func)
m->func(m->cmd);
MOUSE_DO_BIND(m);
SLIST_FOREACH(m, &b->statusmousebinds, next)
MOUSE_DO_BIND(m);
break;
}
if((c = client_gb_win(ev->window)) && c != W->client
&& ev->button == 1 && W->cfocus & CFOCUS_CLICK)
client_focus(c);
}
static void
@ -48,12 +61,18 @@ event_enternotify(XEvent *e)
&& ev->window != W->root)
return;
if(ev->window == W->systray.win || systray_find(ev->window))
return;
if((c = client_gb_win(ev->window))
|| (c = client_gb_frame(ev->window)))
{
if(c->flags & CLIENT_IGNORE_ENTER)
c->flags ^= CLIENT_IGNORE_ENTER;
else if(c != W->client && !(c->flags & CLIENT_TABBED))
else if(c->tag->flags & TAG_IGNORE_ENTER)
c->tag->flags ^= TAG_IGNORE_ENTER;
else if(c != W->client && !(c->flags & CLIENT_TABBED)
&& W->cfocus & CFOCUS_ENTER)
client_focus(c);
}
}
@ -63,11 +82,70 @@ event_clientmessageevent(XEvent *e)
{
XClientMessageEvent *ev = &e->xclient;
struct client *c;
struct _systray *sy;
int type = 0;
while(type < net_last && W->net_atom[type] != ev->message_type)
++type;
/*
* Systray message
* _NET_WM_SYSTRAY_TRAY_OPCODE
*/
if(ev->window == W->systray.win && type == net_system_tray_opcode)
{
if(ev->data.l[1] == XEMBED_EMBEDDED_NOTIFY)
{
systray_add(ev->data.l[2]);
systray_update();
}
else if(ev->data.l[1] == XEMBED_REQUEST_FOCUS)
{
if((sy = systray_find(ev->data.l[2])))
ewmh_send_message(sy->win, sy->win, "_XEMBED", XEMBED_FOCUS_IN,
XEMBED_FOCUS_CURRENT, 0, 0, 0);
}
}
else if(ev->window == W->root)
{
/* WMFS message */
if(ev->data.l[4])
{
/* Manage _WMFS_FUNCTION && _WMFS_CMD */
if(type == wmfs_function || type == wmfs_cmd)
{
Atom rt;
int d;
long unsigned int len, il;
unsigned char *ret = NULL, *ret_cmd = NULL;
void (*func)(Uicb);
if(XGetWindowProperty(EVDPY(e), W->root, W->net_atom[wmfs_function], 0, 65536,
False, W->net_atom[utf8_string], &rt, &d,
&len, &il, &ret) == Success
&& ret && ((func = uicb_name_func((char*)ret))))
{
if(XGetWindowProperty(EVDPY(e), W->root, W->net_atom[wmfs_cmd], 0, 65536,
False, W->net_atom[utf8_string], &rt, &d,
&len, &il, &ret_cmd) == Success
&& len && ret_cmd)
{
func((Uicb)ret_cmd);
XFree(ret_cmd);
}
else
func(NULL);
XFree(ret);
}
}
}
if(type == net_active_window)
if((sy = systray_find(ev->data.l[0])))
XSetInputFocus(W->dpy, sy->win, RevertToNone, CurrentTime);
}
switch(type)
{
/* _NET_WM_STATE */
@ -94,6 +172,21 @@ event_configureevent(XEvent *e)
struct client *c;
if((c = client_gb_win(ev->window)))
{
if(c->flags & CLIENT_FREE)
{
if(ev->value_mask & CWX)
c->geo.x = ev->x;
if(ev->value_mask & CWY)
c->geo.y = ev->y - c->tbarw - c->border - c->border;
if(ev->value_mask & CWWidth)
c->geo.w = ev->width + c->border + c->border;
if(ev->value_mask & CWHeight)
c->geo.h = ev->height + c->tbarw + c->border;
client_moveresize(c, &c->geo);
}
else
{
if(ev->value_mask & CWWidth)
_fac_resize(c, Right, ev->width - c->wgeo.w);
@ -102,6 +195,7 @@ event_configureevent(XEvent *e)
client_apply_tgeo(c->tag);
}
}
else
{
wc.x = ev->x;
@ -121,9 +215,16 @@ event_destroynotify(XEvent *e)
{
XDestroyWindowEvent *ev = &e->xdestroywindow;
struct client *c;
struct _systray *s;
if((c = client_gb_win(ev->window)))
client_remove(c);
else if((s = systray_find(ev->window)))
{
ewmh_set_wm_state(s->win, WithdrawnState);
systray_del(s);
systray_update();
}
}
static void
@ -140,14 +241,23 @@ event_maprequest(XEvent *e)
{
XMapRequestEvent *ev = &e->xmaprequest;
XWindowAttributes at;
struct _systray *s;
/* Which windows to manage */
if(!XGetWindowAttributes(EVDPY(e), ev->window, &at)
|| at.override_redirect)
|| at.override_redirect
|| ewmh_manage_window_type_desktop(ev->window)
|| ewmh_manage_state_sticky(ev->window))
return;
if(!client_gb_win(ev->window))
client_new(ev->window, &at, false);
else if((s = systray_find(ev->window)))
{
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime,
XEMBED_WINDOW_ACTIVATE, 0, 0, 0);
systray_update();
}
}
static void
@ -164,7 +274,9 @@ static void
event_propertynotify(XEvent *e)
{
XPropertyEvent *ev = &e->xproperty;
XWMHints *h;
struct client *c;
struct _systray *s;
if(ev->state == PropertyDelete)
return;
@ -175,26 +287,34 @@ event_propertynotify(XEvent *e)
{
case XA_WM_TRANSIENT_FOR:
break;
case XA_WM_NORMAL_HINTS:
/* client_get_size_hints(c); */
break;
case XA_WM_HINTS:
/*
XWMHints *h;
if((h = XGetWMHints(EVDPY, c->win)) && (h->flags & XUrgencyHint) && c != sel)
case XA_WM_NORMAL_HINTS:
client_get_sizeh(c);
break;
case XA_WM_HINTS:
if((h = XGetWMHints(EVDPY(e), c->win))
&& (h->flags & XUrgencyHint)
&& c->tag != W->screen->seltag)
{
client_urgent(c, True);
c->tag->flags |= TAG_URGENT;
infobar_elem_screen_update(c->screen, ElemTag);
XFree(h);
}
*/
break;
default:
if(ev->atom == XA_WM_NAME || ev->atom == W->net_atom[net_wm_name])
client_get_name(c);
break;
}
}
else if((s = systray_find(ev->window)))
{
systray_state(s);
systray_update();
}
}
static void
@ -202,19 +322,39 @@ event_unmapnotify(XEvent *e)
{
XUnmapEvent *ev = &e->xunmap;
struct client *c;
struct _systray *s;
if((c = client_gb_win(ev->window)) && ev->send_event)
if((c = client_gb_win(ev->window))
&& ev->send_event
&& ev->event == W->root)
{
Atom rt;
unsigned long n, il;
int d;
unsigned char *ret = NULL;
if(XGetWindowProperty(EVDPY(e), c->win, W->net_atom[wm_state], 0, 2,
False, W->net_atom[wm_state], &rt, &d,
&n, &il, &ret) == Success)
if(*ret == NormalState)
client_remove(c);
}
else if((s = systray_find(ev->window)))
{
systray_del(s);
systray_update();
}
}
static void
event_keypress(XEvent *e)
{
XKeyPressedEvent *ev = &e->xkey;
KeySym keysym = XKeycodeToKeysym(EVDPY(e), (KeyCode)ev->keycode, 0);
KeySym keysym = XkbKeycodeToKeysym(EVDPY(e), (KeyCode)ev->keycode, 0, 0);
struct keybind *k;
screen_update_sel();
status_flush_surface();
SLIST_FOREACH(k, &W->h.keybind, next)
if(k->keysym == keysym && KEYPRESS_MASK(k->mod) == KEYPRESS_MASK(ev->state))
@ -236,6 +376,36 @@ event_expose(XEvent *e)
}
}
static void
event_mapnotify(XEvent *e)
{
XMapEvent *ev = &e->xmap;
struct client *c;
struct _systray *s;
if(ev->window != ev->event && !ev->send_event)
return;
if((c = client_gb_win(ev->window)))
client_map(c);
else if((s = systray_find(ev->window)))
{
ewmh_set_wm_state(s->win, NormalState);
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime,
XEMBED_WINDOW_ACTIVATE, 0, 0, 0);
}
}
static void
event_selectionclearevent(XEvent *ev)
{
/* Getting selection if lost it */
if(ev->xselectionclear.window == W->systray.win)
systray_acquire();
systray_update();
}
static void
event_dummy(XEvent *e)
{
@ -259,12 +429,11 @@ event_init(void)
event_handle[Expose] = event_expose;
event_handle[FocusIn] = event_focusin;
event_handle[KeyPress] = event_keypress;
/*event_handle[MapNotify] = event_mapnotify;*/
event_handle[MapNotify] = event_mapnotify;
event_handle[MapRequest] = event_maprequest;
event_handle[MappingNotify] = event_mappingnotify;
event_handle[PropertyNotify] = event_propertynotify;
/*event_handle[ReparentNotify] = event_reparentnotify;*/
/*event_handle[SelectionClear] = event_selectionclearevent;*/
event_handle[SelectionClear] = event_selectionclearevent;
event_handle[UnmapNotify] = event_unmapnotify;
}

View File

@ -6,6 +6,8 @@
#ifndef EVENT_H
#define EVENT_H
#include <X11/XKBlib.h>
#include "wmfs.h"
#define MAX_EV 256

View File

@ -22,6 +22,8 @@ ewmh_init(void)
/* EWMH hints */
W->net_atom[wm_state] = ATOM("WM_STATE");
W->net_atom[wm_class] = ATOM("WM_CLASS");
W->net_atom[wm_name] = ATOM("WM_NAME");
W->net_atom[net_supported] = ATOM("_NET_SUPPORTED");
W->net_atom[net_client_list] = ATOM("_NET_CLIENT_LIST");
W->net_atom[net_frame_extents] = ATOM("_NET_FRAME_EXTENTS");
@ -40,6 +42,7 @@ ewmh_init(void)
W->net_atom[net_supporting_wm_check] = ATOM("_NET_SUPPORTING_WM_CHECK");
W->net_atom[net_wm_window_opacity] = ATOM("_NET_WM_WINDOW_OPACITY");
W->net_atom[net_wm_window_type_normal] = ATOM("_NET_WM_WINDOW_TYPE_NORMAL");
W->net_atom[net_wm_window_type_desktop] = ATOM("_NET_WM_WINDOW_TYPE_DESKTOP");
W->net_atom[net_wm_window_type_dock] = ATOM("_NET_WM_WINDOW_TYPE_DOCK");
W->net_atom[net_wm_window_type_splash] = ATOM("_NET_WM_WINDOW_TYPE_SPLASH");
W->net_atom[net_wm_window_type_dialog] = ATOM("_NET_WM_WINDOW_TYPE_DIALOG");
@ -48,7 +51,9 @@ ewmh_init(void)
W->net_atom[net_wm_state_fullscreen] = ATOM("_NET_WM_STATE_FULLSCREEN");
W->net_atom[net_wm_state_sticky] = ATOM("_NET_WM_STATE_STICKY");
W->net_atom[net_wm_state_demands_attention] = ATOM("_NET_WM_STATE_DEMANDS_ATTENTION");
W->net_atom[net_wm_system_tray_opcode] = ATOM("_NET_SYSTEM_TRAY_OPCODE");
W->net_atom[net_wm_state_hidden] = ATOM("_NET_WM_STATE_HIDDEN");
W->net_atom[net_system_tray_s] = ATOM("_NET_SYSTEM_TRAY_S0");
W->net_atom[net_system_tray_opcode] = ATOM("_NET_SYSTEM_TRAY_OPCODE");
W->net_atom[net_system_tray_message_data] = ATOM("_NET_SYSTEM_TRAY_MESSAGE_DATA");
W->net_atom[net_system_tray_visual] = ATOM("_NET_SYSTEM_TRAY_VISUAL");
W->net_atom[net_system_tray_orientation] = ATOM("_NET_SYSTEM_TRAY_ORIENTATION");
@ -79,12 +84,14 @@ ewmh_init(void)
/* Set _NET_SUPPORTING_WM_CHECK */
XChangeProperty(W->dpy, W->root, W->net_atom[net_supporting_wm_check], XA_WINDOW, 32,
PropModeReplace, (unsigned char*)&W->root, 1);
/*
XChangeProperty(W->dpy, W->root, W->net_atom[net_wm_name], W->net_atom[utf8_string], 8,
PropModeReplace, (unsigned char*)&rootn, strlen(rootn));
XChangeProperty(W->dpy, W->root, ATOM("WM_CLASS"), XA_STRING, 8,
PropModeReplace, (unsigned char*)&class, strlen(class));
PropModeReplace, (unsigned char*)&"wmfs", 4);
XChangeProperty(W->dpy, W->root, W->net_atom[net_wm_name], W->net_atom[utf8_string], 8,
PropModeReplace, (unsigned char*)&"wmfs2", 5);
/*
* Set _NET_WM_PID
XChangeProperty(W->dpy, W->root, W->net_atom[net_wm_pid], XA_CARDINAL, 32,
@ -106,6 +113,56 @@ ewmh_set_wm_state(Window w, int state)
W->net_atom[wm_state], 32, PropModeReplace, d, 2);
}
/*
* _NET_CLIENT_LIST
*/
void
ewmh_get_client_list(void)
{
Window *list;
struct client *c;
int win_n = 0;
SLIST_FOREACH(c, &W->h.client, next)
++win_n;
list = xcalloc(win_n, sizeof(Window));
win_n = 0;
SLIST_FOREACH(c, &W->h.client, next)
list[win_n++] = c->win;
XChangeProperty(W->dpy, W->root, W->net_atom[net_client_list], XA_WINDOW, 32,
PropModeReplace, (unsigned char *)list, win_n);
XFree(list);
}
/*
* Get xembed state
*/
long
ewmh_get_xembed_state(Window win)
{
Atom rf;
int f;
long ret = 0;
unsigned long n, il;
unsigned char *data = NULL;
if(XGetWindowProperty(W->dpy, win, W->net_atom[xembedinfo], 0L, 2, False,
W->net_atom[xembedinfo], &rf, &f, &n, &il, &data) != Success)
return 0;
if(rf == W->net_atom[xembedinfo] && n == 2)
ret = (long)data[1];
if(n && data)
XFree(data);
return ret;
}
void
ewmh_update_wmfs_props(void)
{
@ -118,7 +175,6 @@ ewmh_update_wmfs_props(void)
cts = xcalloc(ns, sizeof(long));
for(i = 0; i < ns; ++i)
{
s = screen_gb_id(i);
@ -139,34 +195,113 @@ void
ewmh_manage_state(long data[], struct client *c)
{
/* _NET_WM_STATE_FULLSCREEN */
if(data[1] == (long)W->net_atom[net_wm_state_fullscreen])
if(data[1] == (long)W->net_atom[net_wm_state_fullscreen]
|| data[2] == (long)W->net_atom[net_wm_state_fullscreen])
{
if(data[0] == _NET_WM_STATE_ADD
|| (data[0] == _NET_WM_STATE_TOGGLE && !(c->flags & CLIENT_FULLSCREEN)))
{
c->flags |= CLIENT_FULLSCREEN;
XChangeProperty(W->dpy, c->win, W->net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace,
(unsigned char*)&W->net_atom[net_wm_state_fullscreen], 1);
XReparentWindow(W->dpy, c->win, W->root, c->screen->geo.x, c->screen->geo.y);
XResizeWindow(W->dpy, c->win, c->screen->geo.w, c->screen->geo.h);
XChangeProperty(W->dpy, c->win, W->net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace,
(unsigned char*)&W->net_atom[net_wm_state_fullscreen], true);
if(c->tag)
client_focus(c);
XRaiseWindow(W->dpy, c->win);
}
else if(data[0] == _NET_WM_STATE_REMOVE
|| (data[0] == _NET_WM_STATE_TOGGLE && c->flags & CLIENT_FULLSCREEN))
else
{
c->flags &= ~CLIENT_FULLSCREEN;
XReparentWindow(W->dpy, c->win, c->frame, c->wgeo.x, c->wgeo.y);
XChangeProperty(W->dpy, c->win, W->net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace,
(unsigned char*)&W->net_atom[net_wm_state_fullscreen], false);
(unsigned char*)0, 0);
XReparentWindow(W->dpy, c->win, c->frame, c->wgeo.x, c->wgeo.y);
if(c->flags & CLIENT_FREE)
client_moveresize(c, &c->geo);
else
layout_fix_hole(c);
}
}
}
bool
ewmh_manage_state_sticky(Window win)
{
Atom *atom, rf;
int f;
unsigned long n, il, i;
unsigned char *data = NULL;
bool is_sticky = false;
if(XGetWindowProperty(W->dpy, win, W->net_atom[net_wm_state], 0L, 0x7FFFFFFFL, false,
XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
{
atom = (Atom*)data;
for(i = 0; i < n; ++i)
{
/* manage _NET_WM_STATE_STICKY */
if(atom[i] == W->net_atom[net_wm_state_sticky])
{
XWindowAttributes at;
XMapWindow(W->dpy, win);
XMapSubwindows(W->dpy, win);
if(XGetWindowAttributes(W->dpy, win, &at))
{
struct geo g;
if(at.x < W->screen->ugeo.x)
g.x = W->screen->ugeo.x;
else if((at.x + at.width) > W->screen->ugeo.w)
g.x = W->screen->ugeo.w - at.width;
else
g.x = at.x;
if(at.y < W->screen->ugeo.y)
g.y = W->screen->ugeo.y;
else if((at.y + at.height) > W->screen->ugeo.h)
g.y = W->screen->ugeo.h - at.height;
else
g.y = at.y;
XMoveWindow(W->dpy, win, g.x, g.y);
}
if(W->client)
{
XUngrabButton(W->dpy, AnyButton, AnyModifier, W->client->win);
XGrabButton(W->dpy, AnyButton, AnyModifier, W->client->win, False,
ButtonMask, GrabModeAsync, GrabModeSync, None, None);
client_frame_update(W->client, &W->client->ncol);
W->client = NULL;
}
XRaiseWindow(W->dpy, win);
XSetInputFocus(W->dpy, win, RevertToPointerRoot, CurrentTime);
XChangeProperty(W->dpy, W->root, W->net_atom[net_active_window], XA_WINDOW, 32,
PropModeReplace, (unsigned char *)&win, 1);
is_sticky = true;
break;
}
}
XFree(data);
}
return is_sticky;
}
void
@ -178,6 +313,20 @@ ewmh_manage_window_type(struct client *c)
unsigned char *data = NULL;
long ldata[5] = { _NET_WM_STATE_ADD };
if(XGetWindowProperty(W->dpy, c->win, W->net_atom[net_wm_window_type], 0L, 0x7FFFFFFFL,
False, XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
{
atom = (Atom*)data;
for(i = 0; i < n; ++i)
{
/* MANAGE _NET_WM_WINDOW_TYPE_DIALOG */
if(atom[i] == W->net_atom[net_wm_window_type_dialog])
c->flags |= CLIENT_FREE;
}
XFree(data);
}
/* _NET_WM_STATE at window mangement */
if(XGetWindowProperty(W->dpy, c->win, W->net_atom[net_wm_state], 0L, 0x7FFFFFFFL, false,
XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
@ -194,3 +343,36 @@ ewmh_manage_window_type(struct client *c)
}
}
bool
ewmh_manage_window_type_desktop(Window win)
{
Atom *atom, rf;
int f;
unsigned long n, il, i;
unsigned char *data = NULL;
bool is_desktop = false;
if(XGetWindowProperty(W->dpy, win, W->net_atom[net_wm_window_type], 0L, 0x7FFFFFFF,
False, XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
{
atom = (Atom*)data;
for(i = 0; i < n; ++i)
{
/* If it is a _NET_WM_WINDOW_TYPE_DESKTOP window */
if(atom[i] == W->net_atom[net_wm_window_type_desktop])
{
/* map it, but don't manage it */
XMapWindow(W->dpy, win);
XMapSubwindows(W->dpy, win);
is_desktop = true;
break;
}
}
XFree(data);
}
return is_desktop;
}

View File

@ -11,12 +11,37 @@
#include <X11/Xutil.h>
#include "wmfs.h"
#include "util.h"
/* EWMH/Xembed const from freedesktop */
#define XEMBED_MAPPED (1 << 0)
#define XEMBED_EMBEDDED_NOTIFY 0
#define XEMBED_WINDOW_ACTIVATE 1
#define XEMBED_WINDOW_DEACTIVATE 2
#define XEMBED_REQUEST_FOCUS 3
#define XEMBED_FOCUS_IN 4
#define XEMBED_FOCUS_OUT 5
#define XEMBED_FOCUS_NEXT 6
#define XEMBED_FOCUS_PREV 7
/* 8-9 were used for XEMBED_GRAB_KEY/XEMBED_UNGRAB_KEY */
#define XEMBED_MODALITY_ON 10
#define XEMBED_MODALITY_OFF 11
#define XEMBED_REGISTER_ACCELERATOR 12
#define XEMBED_UNREGISTER_ACCELERATOR 13
#define XEMBED_ACTIVATE_ACCELERATOR 14
/* Details for XEMBED_FOCUS_IN: */
#define XEMBED_FOCUS_CURRENT 0
#define XEMBED_FOCUS_FIRST 1
#define XEMBED_FOCUS_LAST 2
/* Ewmh hints list */
enum
{
/* ICCCM */
wm_state,
wm_class,
wm_name,
/* EWMH */
net_supported,
net_wm_name,
@ -35,6 +60,7 @@ enum
net_supporting_wm_check,
net_wm_window_opacity,
net_wm_window_type_normal,
net_wm_window_type_desktop,
net_wm_window_type_dock,
net_wm_window_type_splash,
net_wm_window_type_dialog,
@ -44,7 +70,8 @@ enum
net_wm_state_fullscreen,
net_wm_state_sticky,
net_wm_state_demands_attention,
net_wm_system_tray_opcode,
net_wm_state_hidden,
net_system_tray_opcode,
net_system_tray_message_data,
net_system_tray_s,
net_system_tray_visual,
@ -72,10 +99,33 @@ enum
net_last
};
static inline void
ewmh_send_message(Window d, Window w, char *atom, long d0, long d1, long d2, long d3, long d4)
{
XClientMessageEvent e;
e.type = ClientMessage;
e.message_type = ATOM(atom);
e.window = w;
e.format = 32;
e.data.l[0] = d0;
e.data.l[1] = d1;
e.data.l[2] = d2;
e.data.l[3] = d3;
e.data.l[4] = d4;
XSendEvent(W->dpy, d, false, StructureNotifyMask, (XEvent*)&e);
XSync(W->dpy, False);
}
void ewmh_init(void);
void ewmh_set_wm_state(Window w, int state);
void ewmh_get_client_list(void);
long ewmh_get_xembed_state(Window win);
void ewmh_update_wmfs_props(void);
void ewmh_manage_state(long data[], struct client *c);
bool ewmh_manage_state_sticky(Window win);
void ewmh_manage_window_type(struct client *c);
bool ewmh_manage_window_type_desktop(Window win);
#endif /* EWMH_H */

View File

@ -1,73 +0,0 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* File created by David Delassus.
* For license, see COPYING.
*/
#include <sys/stat.h> /* access */
#include "wmfs.h"
#include "util.h"
#include "config.h"
#include "fifo.h"
static void
fifo_open(void)
{
if(W->fifo.fd)
close(W->fifo.fd);
if(!(W->fifo.fd = open(W->fifo.path, O_RDONLY | O_NDELAY, 0)))
warnxl("Can't open FIFO: %s\n", strerror(errno));
}
void
fifo_init(void)
{
xasprintf(&(W->fifo.path), "%s/wmfs-%s.fifo", P_tmpdir, DisplayString(W->dpy));
/* Check if fifo already exists */
if(access(W->fifo.path, F_OK) != -1)
unlink(W->fifo.path);
if(mkfifo(W->fifo.path, 0644) < 0)
warnxl("Can't create FIFO: %s\n", strerror(errno));
fifo_open();
}
static void
fifo_parse(char *cmd)
{
void (*func)(Uicb);
char *p, *arg = NULL;
/* remove trailing newline */
if((p = strchr(cmd, '\n')))
*p = '\0';
/* If an argument is present, delimit function string */
if((p = strchr(cmd, ' ')))
{
*p = '\0';
arg = p + 1;
}
/* call the UICB function, p + 1 is command or NULL */
if((func = uicb_name_func(cmd)))
func(arg);
XSync(W->dpy, false);
}
void
fifo_read(void)
{
char buf[256] = { 0 };
int ret;
if((ret = read(W->fifo.fd, buf, sizeof(buf) - 1)) > 0)
fifo_parse(buf);
else if(!ret)
fifo_open();
}

View File

@ -10,10 +10,25 @@
#include "util.h"
#include "tag.h"
#include "status.h"
#include "systray.h"
#include "client.h"
#define ELEM_FREE_BARWIN(e) \
while(!SLIST_EMPTY(&e->bars)) \
{ \
b = SLIST_FIRST(&e->bars); \
SLIST_REMOVE_HEAD(&e->bars, enext); \
barwin_remove(b); \
}
static void infobar_elem_tag_init(struct element *e);
static void infobar_elem_tag_update(struct element *e);
static void infobar_elem_status_init(struct element *e);
static void infobar_elem_status_update(struct element *e);
static void infobar_elem_systray_init(struct element *e);
static void infobar_elem_systray_update(struct element *e);
static void infobar_elem_launcher_init(struct element *e);
static void infobar_elem_launcher_update(struct element *e);
const struct elem_funcs
{
@ -23,11 +38,9 @@ const struct elem_funcs
} elem_funcs[] =
{
{ 't', infobar_elem_tag_init, infobar_elem_tag_update },
{ 's', infobar_elem_status_init, status_manage },
/* { 'l', infobar_elem_layout_init, infobar_elem_layout_update },
{ 'S', infobar_elem_selbar_init, infobar_elem_selbar_update },
*/
{ 's', infobar_elem_status_init, infobar_elem_status_update },
{ 'y', infobar_elem_systray_init, infobar_elem_systray_update },
{ 'l', infobar_elem_launcher_init, infobar_elem_launcher_update },
{ '\0', NULL, NULL }
};
@ -48,6 +61,17 @@ infobar_elem_tag_init(struct element *e)
j = e->geo.x;
e->geo.h -= (e->infobar->theme->tags_border_width << 1);
e->statusctx = &e->infobar->theme->tags_n_sl;
e->statusctx->flags |= STATUS_BLOCK_REFRESH;
if(SLIST_EMPTY(&e->bars) || (e->infobar->screen->flags & SCREEN_TAG_UPDATE))
{
if((e->infobar->screen->flags & SCREEN_TAG_UPDATE))
{
ELEM_FREE_BARWIN(e);
SLIST_INIT(&e->bars);
}
TAILQ_FOREACH(t, &e->infobar->screen->tags, next)
{
s = draw_textw(e->infobar->theme, t->name) + PAD;
@ -55,6 +79,10 @@ infobar_elem_tag_init(struct element *e)
/* Init barwin */
b = barwin_new(e->infobar->bar->win, j, 0, s, e->geo.h, 0, 0, false);
/* Status doesn't have theme yet */
t->statusctx.theme = e->infobar->theme;
t->statusctx.flags |= STATUS_BLOCK_REFRESH;
/* Set border */
if(e->infobar->theme->tags_border_width)
{
@ -72,8 +100,15 @@ infobar_elem_tag_init(struct element *e)
prev = b;
j += s;
}
e->infobar->screen->elemupdate |= FLAGINT(ElemTag);
}
else
{
SLIST_FOREACH(b, &e->bars, enext)
{
barwin_move(b, j, 0);
j += b->geo.w;
}
}
}
static void
@ -91,15 +126,44 @@ infobar_elem_tag_update(struct element *e)
{
b->fg = e->infobar->theme->tags_s.fg;
b->bg = e->infobar->theme->tags_s.bg;
e->statusctx = &e->infobar->theme->tags_s_sl;
}
else
{
/* Normal tag */
if(SLIST_EMPTY(&t->clients))
{
b->fg = e->infobar->theme->tags_n.fg;
b->bg = e->infobar->theme->tags_n.bg;
e->statusctx = &e->infobar->theme->tags_n_sl;
}
/* Urgent tag */
else if(t->flags & TAG_URGENT)
{
b->fg = e->infobar->theme->tags_u.fg;
b->bg = e->infobar->theme->tags_u.bg;
e->statusctx = &e->infobar->theme->tags_u_sl;
}
/* Occupied tag */
else
{
b->fg = e->infobar->theme->tags_o.fg;
b->bg = e->infobar->theme->tags_o.bg;
e->statusctx = &e->infobar->theme->tags_o_sl;
}
}
barwin_refresh_color(b);
/* Manage status line */
e->statusctx->barwin = b;
status_copy_mousebind(e->statusctx);
status_render(e->statusctx);
t->statusctx.barwin = b;
status_copy_mousebind(&t->statusctx);
status_render(&t->statusctx);
draw_text(b->dr, e->infobar->theme, (PAD >> 1),
TEXTY(e->infobar->theme, e->geo.h), b->fg, t->name);
@ -117,17 +181,123 @@ infobar_elem_status_init(struct element *e)
e->geo.w = e->infobar->geo.w - e->geo.x - (en ? e->infobar->geo.w - en->geo.x : 0);
if(!(b = SLIST_FIRST(&e->bars)))
{
b = barwin_new(e->infobar->bar->win, e->geo.x, 0, e->geo.w, e->geo.h, 0, 0, false);
barwin_refresh_color(b);
SLIST_INSERT_HEAD(&e->bars, b, enext);
e->infobar->statusctx = status_new_ctx(b, e->infobar->theme);
e->infobar->statusctx.status = strdup("wmfs2");
e->infobar->statusctx.update = true;
}
else
{
barwin_move(b, e->geo.x, e->geo.y);
barwin_resize(b, e->geo.w, e->geo.h);
}
b->fg = e->infobar->theme->bars.fg;
b->bg = e->infobar->theme->bars.bg;
barwin_map(b);
}
static void
infobar_elem_status_update(struct element *e)
{
if(e->infobar->statusctx.update)
status_manage(&e->infobar->statusctx);
else
{
status_render(&e->infobar->statusctx);
status_copy_mousebind(&e->infobar->statusctx);
}
}
static void
infobar_elem_systray_init(struct element *e)
{
struct barwin *b;
/* Activate systray mask; no more systray element allowed now */
W->flags |= WMFS_SYSTRAY;
W->systray.infobar = e->infobar;
e->geo.w = systray_get_width();
infobar_elem_placement(e);
if(!(b = SLIST_FIRST(&e->bars)))
{
b = barwin_new(e->infobar->bar->win, e->geo.x, 0, e->geo.w, e->geo.h, 0, 0, false);
XFreePixmap(W->dpy, b->dr);
SLIST_INSERT_HEAD(&e->bars, b, enext);
W->systray.barwin = b;
systray_acquire();
}
else
{
barwin_move(b, e->geo.x, e->geo.y);
barwin_resize(b, e->geo.w, e->geo.h);
}
e->infobar->screen->elemupdate |= FLAGINT(ElemStatus);
e->infobar->status = strdup("wmfs2");
XMoveResizeWindow(W->dpy, W->systray.win, 0, 0, e->geo.w, e->geo.h);
}
static void
infobar_elem_systray_update(struct element *e)
{
(void)e;
systray_update();
}
static void
infobar_elem_launcher_init(struct element *e)
{
struct barwin *b;
if(!(W->flags & WMFS_LAUNCHER))
e->geo.w = 1;
infobar_elem_placement(e);
if(!(b = SLIST_FIRST(&e->bars)))
{
b = barwin_new(e->infobar->bar->win, e->geo.x, 0, e->geo.w, e->geo.h, 0, 0, false);
b->fg = e->infobar->theme->bars.fg;
b->bg = e->infobar->theme->bars.bg;
SLIST_INSERT_HEAD(&e->bars, b, enext);
}
else
{
barwin_move(b, e->geo.x, e->geo.y);
barwin_resize(b, e->geo.w, e->geo.h);
}
barwin_refresh_color(b);
barwin_refresh(b);
}
static void
infobar_elem_launcher_update(struct element *e)
{
struct barwin *b = SLIST_FIRST(&e->bars);
int l;
if(!(W->flags & WMFS_LAUNCHER))
return;
barwin_refresh_color(b);
l = draw_textw(e->infobar->theme, e->data) + 2;
draw_text(b->dr, e->infobar->theme, 1, TEXTY(e->infobar->theme, e->geo.h), b->fg, e->data);
/* Cursor */
XDrawLine(W->dpy, b->dr, W->gc, l, 2, l, e->geo.h - 4);
barwin_refresh(b);
}
#define ELEM_INIT(a) \
@ -136,6 +306,7 @@ infobar_elem_status_init(struct element *e)
SLIST_INIT(&e->bars); \
e->infobar = i; \
e->type = j; \
e->data = NULL; \
e->align = a; \
e->func_init = elem_funcs[j].func_init; \
e->func_update = elem_funcs[j].func_update; \
@ -159,14 +330,15 @@ infobar_elem_init(struct infobar *i)
break;
}
/* Only one systray element in a wmfs session */
if(i->elemorder[n] == 'y' && W->flags & WMFS_SYSTRAY)
continue;
for(j = 0; j < (int)LEN(elem_funcs); ++j)
if(elem_funcs[j].c == i->elemorder[n])
{
ELEM_INIT(Left);
if(TAILQ_EMPTY(&i->elements))
TAILQ_INSERT_HEAD(&i->elements, e, next);
else
TAILQ_INSERT_TAIL(&i->elements, e, next);
e->func_init(e);
@ -183,7 +355,7 @@ infobar_elem_init(struct infobar *i)
for(k = l - 1; k >= n; --k)
{
/* Only one status */
if(i->elemorder[k] == 's')
if(i->elemorder[k] == 's' || (i->elemorder[n] == 'y' && W->flags & WMFS_SYSTRAY))
continue;
for(j = 0; j < (int)LEN(elem_funcs); ++j)
@ -216,30 +388,49 @@ infobar_elem_init(struct infobar *i)
}
void
infobar_elem_update(struct infobar *i)
infobar_elem_update(struct infobar *i, int type)
{
struct element *e;
TAILQ_FOREACH(e, &i->elements, next)
if(i->screen->elemupdate & FLAGINT(e->type))
if(type == e->type || type == -1)
e->func_update(e);
}
void
infobar_elem_remove(struct element *e)
infobar_elem_reinit(struct infobar *i)
{
struct barwin *b;
struct element *e;
TAILQ_REMOVE(&e->infobar->elements, e, next);
barwin_refresh_color(i->bar);
while(!SLIST_EMPTY(&e->bars))
TAILQ_FOREACH(e, &i->elements, next)
{
b = SLIST_FIRST(&e->bars);
SLIST_REMOVE_HEAD(&e->bars, enext);
barwin_remove(b);
/* Status element found, scan from the tail now */
if(e->type == ElemStatus)
{
struct element *ee;
TAILQ_FOREACH_REVERSE(ee, &i->elements, esub, next)
{
if(e == ee)
break;
ee->func_init(ee);
ee->func_update(ee);
}
free(e);
e->func_init(e);
e->func_update(e);
return;
}
e->func_init(e);
e->func_update(e);
}
barwin_refresh(i->bar);
}
struct infobar*
@ -264,8 +455,6 @@ infobar_new(struct screen *s, char *name, struct theme *theme, enum barpos pos,
/* struct elements */
infobar_elem_init(i);
SLIST_INIT(&i->statushead);
/* Render, only if pos is Top or Bottom */
if(!map)
return i;
@ -281,7 +470,7 @@ infobar_new(struct screen *s, char *name, struct theme *theme, enum barpos pos,
void
infobar_refresh(struct infobar *i)
{
infobar_elem_update(i);
infobar_elem_update(i, -1);
barwin_refresh(i->bar);
}
@ -290,13 +479,21 @@ void
infobar_remove(struct infobar *i)
{
struct element *e;
struct barwin *b;
free(i->elemorder);
free(i->name);
free(i->status);
TAILQ_FOREACH(e, &i->elements, next)
infobar_elem_remove(e);
if(i == W->systray.infobar)
systray_freeicons();
while(!TAILQ_EMPTY(&i->elements))
{
e = TAILQ_FIRST(&i->elements);
TAILQ_REMOVE(&i->elements, e, next);
ELEM_FREE_BARWIN(e);
free(e);
}
barwin_remove(i->bar);
@ -319,8 +516,49 @@ infobar_free(struct screen *s)
}
}
void
uicb_infobar_toggle_hide(Uicb iname)
{
struct client *c;
struct infobar *i;
if(iname)
i = infobar_gb_name(iname);
else
i = SLIST_FIRST(&W->screen->infobars);
if(i->pos == BarHide)
{
i->pos = i->opos;
if(infobar_placement(i, i->pos))
{
barwin_map(i->bar);
barwin_map_subwin(i->bar);
barwin_refresh_color(i->bar);
infobar_refresh(i);
}
}
else
{
i->opos = i->pos;
i->pos = BarHide;
barwin_unmap_subwin(i->bar);
barwin_unmap(i->bar);
switch(i->opos)
{
case BarTop:
i->screen->ugeo.y -= i->geo.h;
case BarBottom:
i->screen->ugeo.h += i->geo.h;
case BarHide:
default:
break;
}
}
SLIST_FOREACH(c, &W->h.client, next)
layout_fix_hole(c);
}

View File

@ -8,16 +8,16 @@
#include "wmfs.h"
#include "util.h"
#include "draw.h"
#include "tag.h"
enum { ElemTag = 0, ElemStatus, ElemCustom, ElemLast };
enum { ElemTag = 0, ElemStatus, ElemSystray, ElemLauncher, ElemCustom, ElemLast };
struct infobar *infobar_new(struct screen *s, char *name, struct theme *theme, enum barpos pos, const char *elem);
void infobar_elem_update(struct infobar *i);
void infobar_elem_update(struct infobar *i, int type);
void infobar_refresh(struct infobar *i);
void infobar_remove(struct infobar *i);
void infobar_free(struct screen *s);
void infobar_elem_reinit(struct infobar *i);
/* Basic placement of elements */
static inline void
@ -63,16 +63,13 @@ infobar_placement(struct infobar *i, enum barpos p)
}
static inline void
infobar_elem_screen_update(struct screen *s, int addf)
infobar_elem_screen_update(struct screen *s, int type)
{
struct infobar *i;
s->elemupdate |= FLAGINT(addf);
SLIST_FOREACH(i, &s->infobars, next)
infobar_elem_update(i);
infobar_elem_update(i, type);
s->elemupdate &= ~FLAGINT(addf);
}
static inline struct infobar*
@ -91,4 +88,6 @@ infobar_gb_name(const char *name)
return SLIST_FIRST(&s->infobars);
}
void uicb_infobar_toggle_hide(Uicb iname);
#endif /* INFOBAR_H */

438
src/launcher.c Normal file
View File

@ -0,0 +1,438 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <X11/Xutil.h>
#include "wmfs.h"
#include "event.h"
#include "util.h"
#include "infobar.h"
#include "config.h"
static int
qsort_string_compare(const void * a, const void * b)
{
return (strcmp(*(char **)a, *(char **)b));
}
static char **
complete_on_command(char *start)
{
struct dirent *content;
DIR *dir;
char **paths, *path, *p, **namelist = NULL;
int i, count;
if(!(path = getenv("PATH")) || !start)
return NULL;
/* split PATH into paths */
path = p = xstrdup(path);
for(count = 1, p = path; strchr(p, ':'); ++p, ++count);
paths = xcalloc(count, sizeof(*paths));
for(paths[0] = p = path, count = 1; (p = strchr(p, ':')); ++p, ++count)
{
paths[count] = p + 1;
*p = '\0';
}
paths[count] = NULL;
/* recursively open PATH */
for(i = count = 0; paths[i]; ++i)
{
if(!(dir = opendir(paths[i])))
continue;
while((content = readdir(dir)))
{
if(strncmp(content->d_name, ".", 1)
&& !strncmp(content->d_name, start, strlen(start)))
{
namelist = xrealloc(namelist, ++count, sizeof(*namelist));
namelist[count - 1] = xstrdup(content->d_name + strlen(start));
}
}
closedir(dir);
}
if(count)
{
qsort(namelist, count, sizeof(char *), qsort_string_compare);
namelist = xrealloc(namelist, ++count, sizeof(*namelist));
namelist[count - 1] = NULL;
}
free(paths);
free(path);
return namelist;
}
/*
* Complete a filename or directory name.
* works like complete_on_command.
*/
static char **
complete_on_files(char *start)
{
struct dirent *content = NULL;
struct stat st;
DIR *dir;
char *home, *path, *dirname = NULL;
char **namelist = NULL, *filepath, *p = start;
int count = 0;
/*
* Search the directory to open and set
* the beginning of file to complete on pointer 'p'.
*/
if(*p == '\0' || !strrchr(p, '/'))
path = xstrdup(".");
else
{
if(!(home = getenv("HOME")))
return NULL;
/* remplace ~ by $HOME in dirname */
if(!strncmp(p, "~/", 2) && home)
xasprintf(&dirname, "%s%s", home, p+1);
else
dirname = xstrdup(p);
/* Set p to filename to be complete
* and path the directory containing the file
* /foooooo/baaaaaar/somethinglikethis<tab>
* <---- path - ---><------- p ------>
*/
p = strrchr(dirname, '/');
if(p != dirname)
{
*(p++) = '\0';
path = xstrdup(dirname);
}
else
{
path = xstrdup("/");
p++;
}
}
if((dir = opendir(path)))
{
while((content = readdir(dir)))
{
if(!strcmp(content->d_name, ".")
|| !strcmp(content->d_name, "..")
|| strncmp(content->d_name, p, strlen(p)))
continue;
/* If it's a directory append '/' to the completion */
xasprintf(&filepath, "%s/%s", path, content->d_name);
if(filepath && stat(filepath, &st) != -1)
{
namelist = xrealloc(namelist, ++count, sizeof(*namelist));
if(S_ISDIR(st.st_mode))
xasprintf(&namelist[count - 1], "%s/", content->d_name + strlen(p));
else
namelist[count - 1] = xstrdup(content->d_name + strlen(p));
}
else
warnl("%s", filepath);
free(filepath);
}
closedir(dir);
}
if(count)
{
namelist = xrealloc(namelist, ++count, sizeof(*namelist));
namelist[count - 1] = NULL;
}
free(dirname);
free(path);
return namelist;
}
static void
complete_cache_free(struct launcher_ccache *cache)
{
int i;
/* release memory */
free(cache->start);
if(cache->namelist)
{
for(i = 0; cache->namelist[i]; i++)
free(cache->namelist[i]);
free(cache->namelist);
}
/* init */
cache->hits = 0;
cache->start = NULL;
cache->namelist = NULL;
}
static char *
complete(struct launcher_ccache *cache, char *start)
{
char *p = NULL, *comp = NULL;
if(!start || !cache)
return NULL;
if((p = strrchr(start, ' ')))
p++;
else
p = start;
if(cache->start && !strcmp(cache->start, start))
{
if(cache->namelist && !cache->namelist[cache->hits])
cache->hits = 0;
}
else
{
complete_cache_free(cache);
cache->start = xstrdup(start);
if(p == start)
cache->namelist = complete_on_command(p);
else
cache->namelist = complete_on_files(p);
}
if(cache->namelist && cache->namelist[cache->hits])
comp = cache->namelist[cache->hits];
return comp;
}
#define LAUNCHER_INIT_ELEM(width) \
SLIST_FOREACH(ib, &W->screen->infobars, next) \
{ \
TAILQ_FOREACH(e, &ib->elements, next) \
if(e->type == ElemLauncher) \
{ \
e->geo.w = width; \
e->data = data; \
} \
infobar_elem_reinit(ib); \
}
static void
launcher_process(struct launcher *l)
{
struct infobar *ib;
struct element *e;
struct launcher_ccache cache = {NULL, NULL, 0};
bool loop = true, found = false, lastwastab = false;
char tmpbuf[512] = { 0 }, buf[512] = { 0 };
char tmp[32] = { 0 };
char *p, *data, *arg, *end, *cmd = xstrdup(l->command);
int i, pos = 0, histpos = 0;
void (*func)(Uicb);
XEvent ev;
KeySym ks;
W->flags |= WMFS_LAUNCHER;
/* Prepare elements */
xasprintf(&data, "%s ", l->prompt);
LAUNCHER_INIT_ELEM(l->width);
XGrabKeyboard(W->dpy, W->root, true, GrabModeAsync, GrabModeAsync, CurrentTime);
while(loop)
{
XNextEvent(W->dpy, &ev);
if(ev.type != KeyPress)
{
EVENT_HANDLE(&ev);
continue;
}
/* Get pressed key */
XLookupString(&ev.xkey, tmp, sizeof(tmp), &ks, 0);
/* Check Ctrl-c / Ctrl-d */
if(ev.xkey.state & ControlMask)
{
switch(ks)
{
case XK_c:
case XK_d:
ks = XK_Escape;
break;
case XK_p:
ks = XK_Up;
break;
case XK_n:
ks = XK_Down;
break;
}
}
/* Check if there is a keypad */
if(IsKeypadKey(ks) && ks == XK_KP_Enter)
ks = XK_Return;
/* Manage pressed keys */
switch(ks)
{
case XK_Up:
if(l->nhisto)
{
if(histpos >= (int)l->nhisto)
histpos = 0;
strncpy(buf, l->histo[l->nhisto - ++histpos], sizeof(buf));
pos = strlen(buf);
}
break;
case XK_Down:
if(l->nhisto && histpos > 0 && histpos < (int)l->nhisto)
{
strncpy(buf, l->histo[l->nhisto - --histpos], sizeof(buf));
pos = strlen(buf);
}
break;
case XK_Return:
/* Get function name only, if cmds are added in command */
arg = NULL;
if((p = strchr(cmd, ' ')))
{
*p = '\0';
xasprintf(&arg, "%s %s", p + 1, buf);
}
if((func = uicb_name_func(cmd)))
{
if(arg)
{
func(arg);
free(arg);
}
else
func(buf);
}
/* Histo */
if(l->nhisto + 1 > HISTOLEN)
{
for(i = l->nhisto - 1; i > 1; --i)
strncpy(l->histo[i], l->histo[i - 1], sizeof(l->histo[i]));
l->nhisto = 0;
}
/* Store in histo array */
strncpy(l->histo[l->nhisto++], buf, sizeof(buf));
loop = false;
break;
case XK_Escape:
loop = false;
break;
/* Completion */
case XK_Tab:
buf[pos] = '\0';
if(lastwastab)
++cache.hits;
else
{
cache.hits = 0;
strncpy(tmpbuf, buf, sizeof(tmpbuf));
}
if(pos && (end = complete(&cache, tmpbuf)))
{
strncpy(buf, tmpbuf, sizeof(buf));
strncat(buf, end, sizeof(buf));
found = true;
}
lastwastab = true;
/* start a new round of tabbing */
if(!found)
cache.hits = 0;
pos = strlen(buf);
break;
case XK_BackSpace:
lastwastab = false;
if(pos)
buf[--pos] = '\0';
break;
default:
lastwastab = false;
strncat(buf, tmp, sizeof(tmp));
++pos;
break;
}
free(data);
xasprintf(&data, "%s %s", l->prompt, buf);
/* Update EVERY launcher element of the screen */
SLIST_FOREACH(ib, &W->screen->infobars, next)
{
TAILQ_FOREACH(e, &ib->elements, next)
{
if(e->type != ElemLauncher)
continue;
e->data = data;
e->func_update(e);
}
}
}
XUngrabKeyboard(W->dpy, CurrentTime);
complete_cache_free(&cache);
free(cmd);
free(data);
/* 'Close' launcher elements */
W->flags ^= WMFS_LAUNCHER;
data = NULL;
LAUNCHER_INIT_ELEM(1);
}
void
uicb_launcher(Uicb cmd)
{
struct launcher *l;
if(!cmd)
return;
SLIST_FOREACH(l, &W->h.launcher, next)
if(!strcmp(l->name, cmd))
{
launcher_process(l);
break;
}
}

13
src/launcher.h Normal file
View File

@ -0,0 +1,13 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef LAUNCHER_H
#define LAUNCHER_H
#include "wmfs.h"
void uicb_launcher(Uicb cmd);
#endif /* LAUNCHER_H */

View File

@ -4,6 +4,7 @@
*/
#include <X11/Xutil.h>
#include <X11/XKBlib.h>
#include "layout.h"
#include "config.h"
@ -12,6 +13,9 @@
#include "event.h"
#include "util.h"
/* Shift in client split to keep clients's parent at close arrange */
static int shiftv = 1, shifth = 1;
void
layout_save_set(struct tag *t)
{
@ -23,7 +27,7 @@ layout_save_set(struct tag *t)
l = xcalloc(1, sizeof(struct layout_set));
SLIST_INIT(&l->geos);
SLIST_FOREACH(c, &t->clients, tnext)
FOREACH_NFCLIENT(c, &t->clients, tnext)
{
g = xcalloc(1, sizeof(struct geo_list));
g->geo = c->geo;
@ -49,7 +53,7 @@ layout_apply_set(struct tag *t, struct layout_set *l)
struct client *c;
int nc = 1;
SLIST_FOREACH(c, &t->clients, tnext)
FOREACH_NFCLIENT(c, &t->clients, tnext)
++nc;
/* TODO: Adapt different client number case */
@ -95,8 +99,9 @@ layout_free_set(struct tag *t)
{
struct layout_set *l;
TAILQ_FOREACH(l, &t->sets, next)
while(!TAILQ_EMPTY(&t->sets))
{
l = TAILQ_FIRST(&t->sets);
TAILQ_REMOVE(&t->sets, l, next);
FREE_LIST(geo_list, l->geos);
free(l);
@ -148,7 +153,7 @@ _historic_set(struct tag *t, bool prev)
if(ev.type == KeyPress)
{
XKeyPressedEvent *ke = &ev.xkey;
keysym = XKeycodeToKeysym(W->dpy, (KeyCode)ke->keycode, 0);
keysym = XkbKeycodeToKeysym(W->dpy, (KeyCode)ke->keycode, 0, 0);
_REV_BORDER();
@ -228,20 +233,26 @@ layout_split(struct client *c, bool vertical)
if(vertical)
{
c->geo.w >>= 1;
c->geo.w += shiftv;
geo.x = c->geo.x + c->geo.w;
geo.w >>= 1;
/* Remainder */
geo.w += (og.x + og.w) - (geo.x + geo.w);
shiftv = -shiftv;
}
else
{
c->geo.h >>= 1;
c->geo.h += shifth;
geo.y = c->geo.y + c->geo.h;
geo.h >>= 1;
/* Remainder */
geo.h += (og.y + og.h) - (geo.y + geo.h);
shifth = -shifth;
}
return geo;
@ -275,7 +286,7 @@ layout_split_check_row_dir(struct client *c, struct client *g, enum position p)
struct client *cc;
int s = 0, cs = (LDIR(p) ? g->geo.h : g->geo.w);
SLIST_FOREACH(cc, &c->tag->clients, tnext)
FOREACH_NFCLIENT(cc, &c->tag->clients, tnext)
if(GEO_PARENTROW(cgeo, cc->geo, RPOS(p))
&& GEO_CHECK_ROW(cc->geo, g->geo, p))
{
@ -319,6 +330,8 @@ layout_split_arrange_closed(struct client *ghost)
bool b = false;
enum position p;
if(!(ghost->flags & CLIENT_TILED))
return;
/* Search for single parent for easy resize
* Example case:
@ -347,7 +360,7 @@ layout_split_arrange_closed(struct client *ghost)
&& layout_split_check_row_dir(c, ghost, p))
{
g = c->geo;
SLIST_FOREACH(cc, &c->tag->clients, tnext)
FOREACH_NFCLIENT(cc, &c->tag->clients, tnext)
if(GEO_PARENTROW(g, cc->geo, RPOS(p))
&& GEO_CHECK_ROW(cc->geo, ghost->geo, p))
{
@ -360,26 +373,64 @@ layout_split_arrange_closed(struct client *ghost)
layout_save_set(ghost->tag);
}
/* Integrate a client in split layout: split sc and fill c in new geo */
/*
* Integrate a client in split layout:
* - Check if there is no sc
* - Check if sc is on a different tag than c
* - Check if sc is not in free mode
*
* So from there, sc is not compatible, so we will integrate
* c in the larger tiled client of c tag:
* - Check if the larger client is correct
*
* Checks all failed? Get first tiled client of the tag to integrate in.
* Still no client, it means that c is the first tiled client of the tag, then maximize it.
*/
void
layout_split_integrate(struct client *c, struct client *sc)
{
struct geo g;
bool f = false;
/* No sc */
if(!sc || sc == c || sc->tag != c->tag)
/* No sc or not compatible, get the largest of the tag */
if(!sc
|| sc == c
|| sc->tag != c->tag
|| (sc->flags & CLIENT_FREE)
|| !COMPCLIENT(c, sc))
sc = client_get_larger(c->tag, c->flags & CLIENT_IGNORE_TAG);
/* Largest not correct */
if(!sc || sc == c)
{
/*
* Not even a first client in list, then
* maximize the lonely client
*/
if(!(sc = SLIST_NEXT(SLIST_FIRST(&c->tag->clients), tnext)))
FOREACH_NFCLIENT(sc, &c->tag->clients, tnext)
if(sc != c && !(sc->flags & CLIENT_TABBED))
{
f = true;
break;
}
/* Ok there is no client to integrate in */
if(!f)
{
client_maximize(c);
c->flags |= CLIENT_TILED;
W->flags &= ~WMFS_TABNOC;
return;
}
}
/* Tab Next Opened Client option */
if(W->flags & WMFS_TABNOC && COMPCLIENT(c, sc))
{
W->flags ^= WMFS_TABNOC;
_client_tab(c, sc);
return;
}
/* If there are clients but we can tab with them, split the screen. */
c->flags |= CLIENT_TILED;
g = layout_split(sc, (sc->geo.h < sc->geo.w));
client_moveresize(c, &g);
@ -389,6 +440,7 @@ layout_split_integrate(struct client *c, struct client *sc)
client_fac_hint(sc);
layout_save_set(c->tag);
W->flags &= ~WMFS_TABNOC;
}
/* Arrange inter-clients holes:
@ -407,7 +459,7 @@ layout_split_integrate(struct client *c, struct client *sc)
* |_____|----'| -> |_____|__v__|
* ^^^ void
*/
inline void
void
layout_fix_hole(struct client *c)
{
struct client *cr = client_next_with_pos(c, Right);
@ -460,7 +512,7 @@ layout_rotate(struct tag *t, void (*pfunc)(struct geo*, struct geo*, struct geo*
float f1 = (float)t->screen->ugeo.w / (float)t->screen->ugeo.h;
float f2 = 1 / f1;
SLIST_FOREACH(c, &t->clients, tnext)
FOREACH_NFCLIENT(c, &t->clients, tnext)
{
pfunc(&g, ug, &c->geo);
@ -474,7 +526,7 @@ layout_rotate(struct tag *t, void (*pfunc)(struct geo*, struct geo*, struct geo*
}
/* Rotate sometimes do not set back perfect size.. */
SLIST_FOREACH(c, &t->clients, tnext)
FOREACH_NFCLIENT(c, &t->clients, tnext)
layout_fix_hole(c);
layout_save_set(t);
@ -518,7 +570,7 @@ uicb_layout_vmirror(Uicb cmd)
(void)cmd;
struct client *c;
SLIST_FOREACH(c, &W->screen->seltag->clients, tnext)
FOREACH_NFCLIENT(c, &W->screen->seltag->clients, tnext)
{
c->geo.x = W->screen->ugeo.w - (c->geo.x + c->geo.w);
client_moveresize(c, &c->geo);
@ -533,7 +585,7 @@ uicb_layout_hmirror(Uicb cmd)
(void)cmd;
struct client *c;
SLIST_FOREACH(c, &W->screen->seltag->clients, tnext)
FOREACH_NFCLIENT(c, &W->screen->seltag->clients, tnext)
{
c->geo.y = W->screen->ugeo.h - (c->geo.y + c->geo.h);
client_moveresize(c, &c->geo);
@ -541,3 +593,52 @@ uicb_layout_hmirror(Uicb cmd)
layout_save_set(W->screen->seltag);
}
#define LAYOUT_INTEGRATE_DIR(D) \
void uicb_layout_integrate_##D(Uicb cmd) \
{ \
(void)cmd; \
if(W->client) \
layout_integrate(W->client, D); \
}
static void
layout_integrate(struct client *c, enum position p)
{
struct client *n;
struct client ghost = *c;
if(!(c->flags & CLIENT_TILED))
return;
if((n = client_next_with_pos(c, p))
&& (n->flags & CLIENT_TILED))
{
layout_split_integrate(c, n);
layout_split_arrange_closed(&ghost);
}
}
LAYOUT_INTEGRATE_DIR(Left);
LAYOUT_INTEGRATE_DIR(Right);
LAYOUT_INTEGRATE_DIR(Top);
LAYOUT_INTEGRATE_DIR(Bottom);
void
layout_client(struct client *c)
{
if(c->flags & (CLIENT_IGNORE_LAYOUT | CLIENT_FULLSCREEN))
{
c->flags &= ~CLIENT_IGNORE_LAYOUT;
return;
}
if(c->flags & CLIENT_FREE)
{
layout_split_arrange_closed(c);
c->flags ^= CLIENT_TILED;
client_moveresize(c, &c->geo);
XRaiseWindow(W->dpy, c->frame);
}
else if(!(c->flags & CLIENT_TABBED))
layout_split_integrate(c, c->tag->sel);
}

View File

@ -7,6 +7,7 @@
#define LAYOUT_H
#include "wmfs.h"
#include "client.h"
/* Check lateral direction (if p is Right or Left) */
#define LDIR(P) (P < Top)
@ -33,7 +34,8 @@ void layout_save_set(struct tag *t);
void layout_free_set(struct tag *t);
void layout_split_integrate(struct client *c, struct client *sc);
void layout_split_arrange_closed(struct client *ghost);
inline void layout_fix_hole(struct client *c);
void layout_fix_hole(struct client *c);
void layout_client(struct client *c);
void uicb_layout_vmirror(Uicb cmd);
void uicb_layout_hmirror(Uicb cmd);
void uicb_layout_rotate_left(Uicb cmd);
@ -41,5 +43,12 @@ void uicb_layout_rotate_right(Uicb cmd);
void uicb_layout_prev_set(Uicb cmd);
void uicb_layout_next_set(Uicb cmd);
/* Generated */
void uicb_layout_integrate_Left(Uicb);
void uicb_layout_integrate_Right(Uicb);
void uicb_layout_integrate_Top(Uicb);
void uicb_layout_integrate_Bottom(Uicb);
#endif /* LAYOUT_H */

View File

@ -9,11 +9,14 @@
#include "client.h"
#include "draw.h"
#define _REV_SBORDER(c) draw_reversed_rect(W->root, c, false);
#define _REV_BORDER() \
do { \
SLIST_FOREACH(gc, &c->tag->clients, tnext) \
FOREACH_NFCLIENT(gc, &c->tag->clients, tnext) \
draw_reversed_rect(W->root, gc, true); \
} while(/* CONSTCOND */ 0);
static void
mouse_resize(struct client *c)
{
@ -21,10 +24,16 @@ mouse_resize(struct client *c)
XEvent ev;
Window w;
int d, u, ox, oy, ix, iy;
int mx, my;
XQueryPointer(W->dpy, W->root, &w, &w, &ox, &oy, &d, &d, (uint *)&u);
XQueryPointer(W->dpy, W->root, &w, &w, &ox, &oy, &d, &d, (unsigned int *)&u);
XGrabServer(W->dpy);
if(c->flags & CLIENT_FREE)
{
_REV_SBORDER(c);
}
else
_REV_BORDER();
if(c->flags & CLIENT_TABBED && !(c->flags & CLIENT_TABMASTER))
@ -33,6 +42,8 @@ mouse_resize(struct client *c)
ix = ox;
iy = oy;
c->flags |= CLIENT_MOUSE;
do
{
XMaskEvent(W->dpy, MouseMask | SubstructureRedirectMask, &ev);
@ -40,31 +51,68 @@ mouse_resize(struct client *c)
if(ev.type != MotionNotify)
continue;
mx = ev.xmotion.x_root;
my = ev.xmotion.y_root;
if(c->flags & CLIENT_FREE)
{
_REV_SBORDER(c);
mx -= c->screen->ugeo.x;
my -= c->screen->ugeo.y;
c->geo.w = ((mx - c->geo.x <= c->sizeh[MINW] + c->border + c->border)
? c->sizeh[MINW] + c->border + c->border
: mx - c->geo.x);
c->geo.h = ((my - c->geo.y <= (c->sizeh[MINH] + c->tbarw + c->border))
? c->sizeh[MINH] + c->tbarw + c->border
: my - c->geo.y);
client_geo_hints(&c->geo, (int*)c->sizeh);
/* For border preview cohesion */
c->geo.h += c->tbarw + c->border;
c->geo.w += c->border + c->border;
_REV_SBORDER(c);
}
else
{
_REV_BORDER();
if(ix >= c->geo.x + (c->geo.w >> 1))
_fac_resize(c, Right, ev.xmotion.x_root - ox);
if(ix >= c->rgeo.x + (c->geo.w >> 1))
_fac_resize(c, Right, mx - ox);
else
_fac_resize(c, Left, ox - ev.xmotion.x_root);
_fac_resize(c, Left, ox - mx);
if(iy >= c->geo.y + (c->geo.h >> 1))
_fac_resize(c, Bottom, ev.xmotion.y_root - oy);
if(iy >= c->rgeo.y + (c->geo.h >> 1))
_fac_resize(c, Bottom, my - oy);
else
_fac_resize(c, Top, oy - ev.xmotion.y_root);
_fac_resize(c, Top, oy - my);
ox = ev.xmotion.x_root;
oy = ev.xmotion.y_root;
ox = mx;
oy = my;
_REV_BORDER();
}
XSync(W->dpy, false);
} while(ev.type != ButtonRelease);
if(c->flags & CLIENT_FREE)
{
_REV_SBORDER(c);
client_moveresize(c, &c->geo);
}
else
{
_REV_BORDER();
client_apply_tgeo(c->tag);
layout_save_set(c->tag);
}
c->flags &= ~CLIENT_MOUSE;
XUngrabServer(W->dpy);
}
@ -88,7 +136,6 @@ mouse_drag_tag(struct client *c, Window w)
return NULL;
}
#define _REV_SBORDER(c) draw_reversed_rect(W->root, c, false);
void
mouse_move(struct client *c, void (*func)(struct client*, struct client*))
{
@ -96,13 +143,21 @@ mouse_move(struct client *c, void (*func)(struct client*, struct client*))
struct tag *t = NULL;
XEvent ev;
Window w;
int d, u;
int d, u, ox, oy;
int ocx, ocy;
ocx = c->geo.x;
ocy = c->geo.y;
if(c->flags & CLIENT_TABBED && !(c->flags & CLIENT_TABMASTER))
c = c->tabmaster;
XQueryPointer(W->dpy, W->root, &w, &w, &ox, &oy, &d, &d, (uint *)&u);
_REV_SBORDER(c);
c->flags |= CLIENT_MOUSE;
do
{
XMaskEvent(W->dpy, MouseMask | SubstructureRedirectMask, &ev);
@ -110,13 +165,22 @@ mouse_move(struct client *c, void (*func)(struct client*, struct client*))
if(ev.type != MotionNotify)
continue;
if(!func && c->flags & CLIENT_FREE)
{
_REV_SBORDER(c);
c->geo.x = (ocx + (ev.xmotion.x_root - ox));
c->geo.y = (ocy + (ev.xmotion.y_root - oy));
_REV_SBORDER(c);
}
else
{
c2 = NULL;
XQueryPointer(W->dpy, W->root, &w, &w, &d, &d, &d, &d, (uint *)&u);
if(!(c2 = client_gb_win(w)))
if(!(c2 = client_gb_frame(w)))
c2 = client_gb_titlebar(w);
if(c2)
if((c2 = client_gb_win(w)) || (c2 = client_gb_frame(w)) || (c2 = client_gb_titlebar(w)))
{
if(c2 != last)
{
@ -127,6 +191,7 @@ mouse_move(struct client *c, void (*func)(struct client*, struct client*))
}
else
t = mouse_drag_tag(c, w);
}
XSync(W->dpy, false);
@ -137,7 +202,15 @@ mouse_move(struct client *c, void (*func)(struct client*, struct client*))
else if(t && t != (struct tag*)c)
tag_client(t, c);
else
{
_REV_SBORDER(c);
/* No func mean free client resize */
if(!func)
client_moveresize(c, &c->geo);
}
c->flags &= ~CLIENT_MOUSE;
}
void
@ -155,7 +228,7 @@ uicb_mouse_move(Uicb cmd)
(void)cmd;
if(W->client && mouse_check_client(W->client))
mouse_move(W->client, client_swap2);
mouse_move(W->client, (W->client->flags & CLIENT_FREE ? NULL : client_swap2));
}
void
@ -165,4 +238,5 @@ uicb_mouse_tab(Uicb cmd)
if(W->client && mouse_check_client(W->client))
mouse_move(W->client, _client_tab);
}

View File

@ -42,7 +42,7 @@ string_to_opt(char *s)
ret.fnum = strtod(s, NULL);
ret.boolean = (!strcmp(s, "true")
|| !strcmp(s, "true")
|| !strcmp(s, "True")
|| !strcmp(s, "TRUE")
|| !strcmp(s, "1"));

View File

@ -21,6 +21,7 @@ screen_new(struct geo *g, int id)
s->geo = s->ugeo = *g;
s->seltag = NULL;
s->id = id;
s->flags = 0;
TAILQ_INIT(&s->tags);
SLIST_INIT(&s->infobars);
@ -101,10 +102,10 @@ screen_select(struct screen *s)
void
uicb_screen_next(Uicb cmd)
{
struct screen *s;
struct screen *s = SLIST_NEXT(W->screen, next);
(void)cmd;
if(!(s = SLIST_NEXT(W->screen, next)))
if(!s)
s = SLIST_FIRST(&W->h.screen);
screen_select(s);
@ -113,51 +114,39 @@ uicb_screen_next(Uicb cmd)
void
uicb_screen_prev(Uicb cmd)
{
struct screen *s;
struct screen *s = SLIST_FIRST(&W->h.screen);
(void)cmd;
SLIST_FOREACH(s, &W->h.screen, next)
if(SLIST_NEXT(W->screen, next) == s)
{
while(SLIST_NEXT(s, next) && SLIST_NEXT(s, next) != s)
s = SLIST_NEXT(s, next);
screen_select(s);
return;
}
screen_select(SLIST_FIRST(&W->h.screen));
}
static void
screen_move_client(struct client *c, struct screen *s)
{
tag_client(s->seltag, c);
}
void
uicb_screen_move_client_next(Uicb cmd)
{
struct screen *s;
struct screen *s = SLIST_NEXT(W->screen, next);
(void)cmd;
if(!(s = SLIST_NEXT(W->screen, next)))
if(!s)
s = SLIST_FIRST(&W->h.screen);
screen_move_client(W->client, s);
if(W->client)
tag_client(s->seltag, W->client);
}
void
uicb_screen_move_client_prev(Uicb cmd)
{
struct screen *s;
struct screen *s = SLIST_FIRST(&W->h.screen);
(void)cmd;
SLIST_FOREACH(s, &W->h.screen, next)
if(SLIST_NEXT(W->screen, next) == s)
{
screen_move_client(W->client, s);
return;
}
while(SLIST_NEXT(s, next) && SLIST_NEXT(s, next) != s)
s = SLIST_NEXT(s, next);
screen_move_client(W->client, SLIST_FIRST(&W->h.screen));
if(W->client)
tag_client(s->seltag, W->client);
}
void

View File

@ -22,22 +22,26 @@ screen_gb_id(int id)
}
static inline struct screen*
screen_gb_mouse(void)
screen_gb_geo(int x, int y)
{
struct screen *s;
SLIST_FOREACH(s, &W->h.screen, next)
if(INAREA(x, y, s->geo))
return s;
return SLIST_FIRST(&W->h.screen);
}
static inline struct screen*
screen_gb_mouse(void)
{
Window w;
int d, x, y;
XQueryPointer(W->dpy, W->root, &w, &w, &x, &y, &d, &d, (unsigned int *)&d);
SLIST_FOREACH(s, &W->h.screen, next)
if(INAREA(x, y, s->geo))
break;
if(!s)
s = SLIST_FIRST(&W->h.screen);
return s;
return screen_gb_geo(x, y);
}
void screen_init(void);

View File

@ -8,10 +8,11 @@
#include "config.h"
#include "infobar.h"
#include "util.h"
#include "draw.h"
#include <string.h>
static struct status_seq*
struct status_seq*
status_new_seq(char type, int narg, int minarg, char *args[], int *shift)
{
struct status_seq *sq = xcalloc(1, sizeof(struct status_seq));
@ -33,17 +34,124 @@ status_new_seq(char type, int narg, int minarg, char *args[], int *shift)
return sq;
}
struct status_ctx
status_new_ctx(struct barwin *b, struct theme *t)
{
struct status_ctx ctx = { .barwin = b, .theme = t };
SLIST_INIT(&ctx.statushead);
SLIST_INIT(&ctx.gcache);
return ctx;
}
static void
status_gcache_free(struct status_ctx *ctx)
{
struct status_gcache *gc;
while(!SLIST_EMPTY(&ctx->gcache))
{
gc = SLIST_FIRST(&ctx->gcache);
SLIST_REMOVE_HEAD(&ctx->gcache, next);
free(gc->datas);
free(gc->name);
free(gc);
}
}
void
status_free_ctx(struct status_ctx *ctx)
{
free(ctx->status);
status_flush_list(ctx);
status_gcache_free(ctx);
}
static void
status_graph_draw(struct status_ctx *ctx, struct status_seq *sq, struct status_gcache *gc)
{
int max = 0;
int i, j, y;
float c;
int ys = sq->geo.y + sq->geo.h - 1;
/* If invalid maximum, we have to compute it ourselves */
if(sq->data[2] <= 0)
{
for(i = sq->geo.x + sq->geo.w - 1, j = gc->ndata - 1;
j >= 0 && i >= sq->geo.x;
--j, --i)
{
if(gc->datas[j] > max)
max = gc->datas[j];
}
}
else
max = sq->data[2];
XSetForeground(W->dpy, W->gc, sq->color2);
for(i = sq->geo.x + sq->geo.w - 1, j = gc->ndata - 1;
j >= 0 && i >= sq->geo.x;
--j, --i)
{
/* You divided by zero didn't you? */
if(gc->datas[j])
{
c = (float)max / (float)gc->datas[j];
y = ys - (sq->geo.h / (c > 1 ? c : 1)) + 1;
draw_line(ctx->barwin->dr, i, y, i, ys);
}
}
}
static void
status_graph_process(struct status_ctx *ctx, struct status_seq *sq, char *name)
{
int j;
struct status_gcache *gc;
/* Graph already exist and have a cache */
SLIST_FOREACH(gc, &ctx->gcache, next)
if(!strcmp(name, gc->name))
{
/* shift buffer to remove unused old value */
if(gc->ndata > (sq->geo.w << 1))
for(gc->ndata /= 2, j = 0;
j < gc->ndata;
gc->datas[j] = gc->datas[j + gc->ndata], ++j);
gc->datas[gc->ndata++] = sq->data[1];
status_graph_draw(ctx, sq, gc);
return;
}
if(sq->data[1] > sq->data[2])
sq->data[1] = sq->data[2];
/* No? Make a cache for it */
gc = xcalloc(1, sizeof(struct status_gcache));
gc->name = xstrdup(name);
gc->ndata = 1;
gc->datas = xcalloc(sq->geo.w << 2, sizeof(int));
gc->datas[0] = sq->data[1];
SLIST_INSERT_HEAD(&ctx->gcache, gc, next);
status_graph_draw(ctx, sq, gc);
}
/* Parse mousebind sequence next normal sequence: \<seq>[](button;func;cmd) */
static char*
status_parse_mouse(struct status_seq *sq, struct element *e, char *str)
status_parse_mouse(struct status_seq *sq, char *str)
{
struct mousebind *m;
struct barwin *b = SLIST_FIRST(&e->bars);
char *end, *arg[3] = { NULL };
int i;
if(*str != '(' || !(end = strchr(str, ')')))
return str + 1;
return str;
i = parse_args(++str, ';', ')', 3, arg);
@ -54,7 +162,6 @@ status_parse_mouse(struct status_seq *sq, struct element *e, char *str)
m->func = uicb_name_func(arg[1]);
m->cmd = (i > 1 ? xstrdup(arg[2]) : NULL);
SLIST_INSERT_HEAD(&b->mousebinds, m, next);
SLIST_INSERT_HEAD(&sq->mousebinds, m, snext);
return end + 1;
@ -66,23 +173,28 @@ status_parse_mouse(struct status_seq *sq, struct element *e, char *str)
str = end + 2; \
continue; \
}
static void
status_parse(struct element *e)
void
status_parse(struct status_ctx *ctx)
{
struct status_seq *sq, *prev = NULL;
int i, shift = 0;
char *dstr = xstrdup(e->infobar->status), *sauv = dstr;
char type, *p, *end, *arg[6] = { NULL };
int i, tmp, shift = 0;
char *dstr = xstrdup(ctx->status), *sauv = dstr;
char type, *p, *pp, *end, *arg[10] = { NULL };
for(; *dstr; ++dstr)
{
/* Check if this is a sequence */
if(*dstr != '\\')
if(*dstr != '^' && *dstr != '\\')
continue;
p = ++dstr;
if(!(strchr("sR", *p)) || !(end = strchr(p, ']')))
/* Search for correct end of sequence (] without \ behind) */
if((end = strchr(p, ']')))
while(*(end - 1) == '\\')
end = strchr(end + 1, ']');
if(!(strchr("sRpPig", *p)) || !end)
continue;
/* Then parse & list it */
@ -99,6 +211,10 @@ status_parse(struct element *e)
sq->color = color_atoh(arg[1 + shift]);
sq->str = xstrdup(arg[2 + shift]);
/* Remove \ from string */
for(pp = sq->str; (pp = strchr(sq->str, '\\'));)
memmove(pp, pp + 1, strlen(pp));
break;
/*
@ -114,16 +230,83 @@ status_parse(struct element *e)
sq->color = color_atoh(arg[3 + shift]);
break;
/*
* Progress bar sequence: \p[left/right;w;h;bord;val;valmax;bg;fg] OR x;y
* Position bar sequence: \P[left/right;w;h;tickbord;val;valmax;bg;fg] OR x;y
*/
case 'p':
case 'P':
i = parse_args(p + 2, ';', ']', 9, arg);
STATUS_CHECK_ARGS(i, 7, 8, dstr, end);
sq = status_new_seq(type, i, 7, arg, &shift);
sq->geo.w = ATOI(arg[1 + shift]);
sq->geo.h = ATOI(arg[2 + shift]);
sq->data[0] = ATOI(arg[3 + shift]); /* Border */
sq->data[1] = ((tmp = ATOI(arg[4 + shift])) ? tmp : 1); /* Value */
sq->data[2] = ATOI(arg[5 + shift]); /* Value Max */
sq->color = color_atoh(arg[6 + shift]);
sq->color2 = color_atoh(arg[7 + shift]);
break;
/*
* Graph sequence: \g[left/right;w;h;val;valmax;bg;fg;name] OR x;y
*/
case 'g':
i = parse_args(p + 2, ';', ']', 9, arg);
STATUS_CHECK_ARGS(i, 7, 8, dstr, end);
sq = status_new_seq(type, i, 7, arg, &shift);
sq->geo.w = ATOI(arg[1 + shift]);
sq->geo.h = ATOI(arg[2 + shift]);
sq->data[1] = ATOI(arg[3 + shift]); /* Value */
sq->data[2] = ATOI(arg[4 + shift]); /* Value Max */
sq->color = color_atoh(arg[5 + shift]);
sq->color2 = color_atoh(arg[6 + shift]);
sq->str = xstrdup(arg[7 + shift]);
break;
/*
* Image sequence: \i[left/right;w;h;/path/img] OR \i[x;y;w;h;/path/img]
*/
#ifdef HAVE_IMLIB2
case 'i':
i = parse_args(p + 2, ';', ']', 5, arg);
STATUS_CHECK_ARGS(i, 3, 4, dstr, end);
sq = status_new_seq(type, i, 3, arg, &shift);
sq->geo.w = ATOI(arg[1 + shift]);
sq->geo.h = ATOI(arg[2 + shift]);
sq->str = xstrdup(arg[3 + shift]);
break;
#endif /* HAVE_IMLIB2 */
}
SLIST_INSERT_TAIL(&e->infobar->statushead, sq, next, prev);
if(sq->align == Right)
SLIST_INSERT_HEAD(&ctx->statushead, sq, next);
else
SLIST_INSERT_TAIL(&ctx->statushead, sq, next, prev);
/*
* Optional mousebind sequence(s) \<seq>[](button;func;cmd)
* Parse it while there is a mousebind sequence.
*/
dstr = ++end;
while((*(dstr = status_parse_mouse(sq, e, dstr)) == '('));
dstr = end + 1;
do
dstr = status_parse_mouse(sq, dstr);
while(*dstr == '(');
--dstr;
prev = sq;
}
@ -139,32 +322,41 @@ status_parse(struct element *e)
} \
else if(align == Right) \
{ \
sq->geo.x = e->geo.w - right - sq->geo.w; \
sq->geo.x = ctx->barwin->geo.w - right - sq->geo.w; \
right += sq->geo.w; \
}
#define STORE_MOUSEBIND() \
if(!SLIST_EMPTY(&sq->mousebinds)) \
SLIST_FOREACH(m, &sq->mousebinds, snext) \
m->area = sq->geo;
#define NOALIGN_Y() \
if(sq->align != NoAlign) \
sq->geo.y = (ctx->barwin->geo.h >> 1) - (sq->geo.h >> 1);
static void
status_apply_list(struct element *e)
status_apply_list(struct status_ctx *ctx)
{
struct status_seq *sq;
struct barwin *b = SLIST_FIRST(&e->bars);
struct mousebind *m;
int left = 0, right = 0;
struct geo g;
int left = 0, right = 0, w, h;
SLIST_FOREACH(sq, &e->infobar->statushead, next)
SLIST_FOREACH(sq, &ctx->statushead, next)
{
switch(sq->type)
{
/* Text */
case 's':
sq->geo.w = draw_textw(e->infobar->theme, sq->str);
sq->geo.h = e->infobar->theme->font.height;
sq->geo.w = draw_textw(ctx->theme, sq->str);
sq->geo.h = ctx->theme->font.height;
if(sq->align != NoAlign)
sq->geo.y = TEXTY(e->infobar->theme, e->geo.h);
sq->geo.y = TEXTY(ctx->theme, ctx->barwin->geo.h);
STATUS_ALIGN(sq->align);
draw_text(b->dr, e->infobar->theme, sq->geo.x, sq->geo.y, sq->color, sq->str);
draw_text(ctx->barwin->dr, ctx->theme, sq->geo.x, sq->geo.y, sq->color, sq->str);
if(!SLIST_EMPTY(&sq->mousebinds))
SLIST_FOREACH(m, &sq->mousebinds, snext)
@ -177,75 +369,259 @@ status_apply_list(struct element *e)
/* Rectangle */
case 'R':
if(sq->align != NoAlign)
sq->geo.y = (e->geo.h >> 1) - (sq->geo.h >> 1);
NOALIGN_Y();
STATUS_ALIGN(sq->align);
draw_rect(b->dr, sq->geo, sq->color);
draw_rect(ctx->barwin->dr, &sq->geo, sq->color);
if(!SLIST_EMPTY(&sq->mousebinds))
SLIST_FOREACH(m, &sq->mousebinds, snext)
m->area = sq->geo;
STORE_MOUSEBIND();
break;
/* Progress */
case 'p':
NOALIGN_Y();
STATUS_ALIGN(sq->align);
draw_rect(ctx->barwin->dr, &sq->geo, sq->color);
/* Progress bar geo */
g.x = sq->geo.x + sq->data[0];
g.y = sq->geo.y + sq->data[0];
g.w = sq->geo.w - sq->data[0] - sq->data[0];
g.h = sq->geo.h - sq->data[0] - sq->data[0];
if(sq->data[1] > sq->data[2])
sq->data[1] = sq->data[2];
if(sq->geo.w > sq->geo.h)
g.w /= ((float)sq->data[2] / (float)sq->data[1]);
else
{
g.y += g.h;
g.h /= ((float)sq->data[2] / (float)sq->data[1]);
g.y -= g.h;
}
draw_rect(ctx->barwin->dr, &g, sq->color2);
STORE_MOUSEBIND();
break;
/* Position */
case 'P':
NOALIGN_Y();
STATUS_ALIGN(sq->align);
draw_rect(ctx->barwin->dr, &sq->geo, sq->color);
if(sq->data[1] > sq->data[2])
sq->data[1] = sq->data[2];
g.x = sq->geo.x + ((sq->geo.w - sq->data[0]) / ((float)sq->data[2] / (float)sq->data[1]));
g.y = sq->geo.y;
g.w = sq->data[0];
g.h = sq->geo.h;
draw_rect(ctx->barwin->dr, &g, sq->color2);
STORE_MOUSEBIND();
break;
/* Graph */
case 'g':
NOALIGN_Y();
STATUS_ALIGN(sq->align);
draw_rect(ctx->barwin->dr, &sq->geo, sq->color);
status_graph_process(ctx, sq, sq->str);
STORE_MOUSEBIND();
break;
/* Image */
#ifdef HAVE_IMLIB2
case 'i':
draw_image_load(sq->str, &w, &h);
if(sq->geo.w <= 0)
sq->geo.w = w;
if(sq->geo.h <= 0)
sq->geo.h = h;
if(sq->align != NoAlign)
sq->geo.y = (ctx->barwin->geo.h >> 1) - (sq->geo.h >> 1);
STATUS_ALIGN(sq->align);
draw_image(ctx->barwin->dr, &sq->geo);
STORE_MOUSEBIND();
break;
#endif /* HAVE_IMLIB2 */
}
}
}
/* Render current statustext of an element */
void
status_render(struct element *e)
status_render(struct status_ctx *ctx)
{
struct barwin *b = SLIST_FIRST(&e->bars);
if(!e->infobar->status)
if(!ctx->status)
return;
barwin_refresh_color(b);
if(!(ctx->flags & STATUS_BLOCK_REFRESH))
barwin_refresh_color(ctx->barwin);
/* Use simple text instead sequence if no sequence found */
if(SLIST_EMPTY(&e->infobar->statushead))
if(SLIST_EMPTY(&ctx->statushead))
{
int l = draw_textw(e->infobar->theme, e->infobar->status);
draw_text(b->dr, e->infobar->theme, e->geo.w - l,
TEXTY(e->infobar->theme, e->geo.h), b->fg, e->infobar->status);
int l = draw_textw(ctx->theme, ctx->status);
draw_text(ctx->barwin->dr, ctx->theme, ctx->barwin->geo.w - l,
TEXTY(ctx->theme, ctx->barwin->geo.h), ctx->barwin->fg, ctx->status);
}
else
status_apply_list(e);
status_apply_list(ctx);
barwin_refresh(b);
barwin_refresh(ctx->barwin);
}
/* Parse and render statustext */
void
status_manage(struct element *e)
status_flush_list(struct status_ctx *ctx)
{
struct status_seq *sq;
struct mousebind *m;
struct barwin *b = SLIST_FIRST(&e->bars);
/*
* Flush previous linked list of status sequences
* and mousebind of status barwin
*/
while(!SLIST_EMPTY(&e->infobar->statushead))
/* Flush previous linked list of status sequences */
while(!SLIST_EMPTY(&ctx->statushead))
{
sq = SLIST_FIRST(&e->infobar->statushead);
SLIST_REMOVE_HEAD(&e->infobar->statushead, next);
free(sq->str);
free(sq);
}
while(!SLIST_EMPTY(&b->mousebinds))
sq = SLIST_FIRST(&ctx->statushead);
SLIST_REMOVE_HEAD(&ctx->statushead, next);
while(!SLIST_EMPTY(&sq->mousebinds))
{
m = SLIST_FIRST(&b->mousebinds);
SLIST_REMOVE_HEAD(&b->mousebinds, next);
m = SLIST_FIRST(&sq->mousebinds);
SLIST_REMOVE_HEAD(&sq->mousebinds, snext);
free((void*)m->cmd);
free(m);
}
status_parse(e);
status_render(e);
free(sq->str);
free(sq);
}
SLIST_INIT(&ctx->statushead);
}
void
status_copy_mousebind(struct status_ctx *ctx)
{
struct mousebind *m;
struct status_seq *sq;
if(!ctx->barwin)
return;
/* Flush barwin head of status mousebinds */
SLIST_INIT(&ctx->barwin->statusmousebinds);
SLIST_FOREACH(sq, &ctx->statushead, next)
{
SLIST_FOREACH(m, &sq->mousebinds, snext)
SLIST_INSERT_HEAD(&ctx->barwin->statusmousebinds, m, next);
}
}
/* Parse and render statustext */
void
status_manage(struct status_ctx *ctx)
{
if(!ctx->status)
return;
ctx->update = false;
status_flush_list(ctx);
status_parse(ctx);
status_render(ctx);
status_copy_mousebind(ctx);
}
void
status_flush_surface(void)
{
struct barwin *b;
while(!SLIST_EMPTY(&W->h.vbarwin))
{
b = SLIST_FIRST(&W->h.vbarwin);
SLIST_REMOVE_HEAD(&W->h.vbarwin, vnext);
barwin_remove(b);
}
}
static void
status_surface(int x, int y, int w, int h, Color bg, char *status)
{
struct barwin *b;
struct screen *s;
struct status_ctx ctx;
int d;
Window rw;
if(!status)
return;
if(x + y < 0)
XQueryPointer(W->dpy, W->root, &rw, &rw, &x, &y, &d, &d, (unsigned int *)&d);
s = screen_gb_geo(x, y);
if(x + w > s->geo.x + s->geo.w)
x -= w;
if(y + h > s->geo.y + s->geo.h)
y -= h;
b = barwin_new(W->root, x, y, w, h, 0, bg, false);
barwin_map(b);
/* Use client theme */
ctx = status_new_ctx(b, W->ctheme);
ctx.status = xstrdup(status);
SLIST_INSERT_HEAD(&W->h.vbarwin, b, vnext);
status_manage(&ctx);
status_free_ctx(&ctx);
}
void
uicb_status_surface(Uicb cmd)
{
char *p, *ccmd = xstrdup(cmd);
int s, w, h, x = -1, y = -1;
Color bg;
if(!ccmd || !(p = strchr(ccmd, ' ')))
return;
*p = '\0';
++p;
if(!(((s = sscanf(ccmd, "%d,%d,#%x", &w, &h, &bg)) == 3)
|| (s = sscanf(ccmd, "%d,%d,%d,%d,#%x", &x, &y, &w, &h, &bg)) == 5))
{
free(ccmd);
return;
}
status_surface(x, y, w, h, bg, p);
free(ccmd);
}
/* Syntax: "<infobar name> <status string>" */
@ -268,8 +644,9 @@ uicb_status(Uicb cmd)
SLIST_FOREACH(ib, &s->infobars, next)
if(!strcmp(cmd, ib->name))
{
free(ib->status);
ib->status = xstrdup(p);
free(ib->statusctx.status);
ib->statusctx.status = xstrdup(p);
ib->statusctx.update = true;
infobar_elem_screen_update(s, ElemStatus);
}
}

View File

@ -8,8 +8,16 @@
#include "wmfs.h"
void status_render(struct element *e);
void status_manage(struct element *e);
struct status_ctx status_new_ctx(struct barwin *b, struct theme *t);
void status_free_ctx(struct status_ctx *ctx);
void status_flush_list(struct status_ctx *ctx);
void status_flush_mousebind(struct status_ctx *ctx);
void status_copy_mousebind(struct status_ctx *ctx);
void status_parse(struct status_ctx *ctx);
void status_render(struct status_ctx *ctx);
void status_manage(struct status_ctx *ctx);
void status_flush_surface(void);
void uicb_status(Uicb cmd);
void uicb_status_surface(Uicb cmd);
#endif /* STATUS_H */

200
src/systray.c Normal file
View File

@ -0,0 +1,200 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#include "wmfs.h"
#include "systray.h"
#include "ewmh.h"
#include "infobar.h"
#define SYSTRAY_SPACING (2)
void
systray_acquire(void)
{
Window w = 0;
XSetWindowAttributes wattr =
{
.event_mask = ButtonPressMask | ExposureMask,
.override_redirect = true,
.background_pixmap = ParentRelative,
.background_pixel = W->systray.infobar->theme->bars.bg,
};
if(!(W->flags & WMFS_SYSTRAY) || W->systray.win)
return;
if(XGetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s]) != None)
{
warnx("Can't initialize system tray: owned by another process.");
return;
}
SLIST_INIT(&W->systray.head);
/* Init systray window */
w = XCreateSimpleWindow(W->dpy, W->systray.barwin->win, 0, 0,
W->systray.barwin->geo.h, W->systray.barwin->geo.h, 0, 0, 0);
XChangeWindowAttributes(W->dpy, w, CWEventMask | CWOverrideRedirect | CWBackPixel, &wattr);
XSelectInput(W->dpy, w, KeyPressMask | ButtonPressMask);
XMapRaised(W->dpy, w);
XSetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s], w, CurrentTime);
if(XGetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s]) != w)
{
warnl("System tray: can't get systray manager");
systray_freeicons();
return;
}
ewmh_send_message(W->root, W->root, "MANAGER", CurrentTime,
W->net_atom[net_system_tray_s], w, 0, 0);
XSync(W->dpy, false);
W->systray.win = w;
}
void
systray_add(Window win)
{
struct _systray *s;
if(!(W->flags & WMFS_SYSTRAY))
return;
s = xcalloc(1, sizeof(struct _systray));
s->win = win;
s->geo.h = W->systray.barwin->geo.h;
s->geo.w = W->systray.barwin->geo.h + SYSTRAY_SPACING;
ewmh_set_wm_state(s->win, NormalState);
XSelectInput(W->dpy, s->win, StructureNotifyMask | PropertyChangeMask| EnterWindowMask | FocusChangeMask);
XReparentWindow(W->dpy, s->win, W->systray.win, 0, 0);
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime,
XEMBED_EMBEDDED_NOTIFY, 0, W->systray.win, 0);
SLIST_INSERT_HEAD(&W->systray.head, s, next);
W->systray.redim = true;
}
void
systray_del(struct _systray *s)
{
if(!(W->flags & WMFS_SYSTRAY))
return;
SLIST_REMOVE(&W->systray.head, s, _systray, next);
free(s);
W->systray.redim = true;
}
void
systray_state(struct _systray *s)
{
long flags;
int code = 0;
if(!(W->flags & WMFS_SYSTRAY) || !(flags = ewmh_get_xembed_state(s->win)))
return;
if(flags & XEMBED_MAPPED)
{
code = XEMBED_WINDOW_ACTIVATE;
XMapRaised(W->dpy, s->win);
ewmh_set_wm_state(s->win, NormalState);
}
else
{
code = XEMBED_WINDOW_DEACTIVATE;
XUnmapWindow(W->dpy, s->win);
ewmh_set_wm_state(s->win, WithdrawnState);
}
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime, code, 0, 0, 0);
}
void
systray_freeicons(void)
{
struct _systray *i;
if(!(W->flags & WMFS_SYSTRAY))
return;
while(!SLIST_EMPTY(&W->systray.head))
{
i = SLIST_FIRST(&W->systray.head);
SLIST_REMOVE_HEAD(&W->systray.head, next);
XUnmapWindow(W->dpy, i->win);
XReparentWindow(W->dpy, i->win, W->root, 0, 0);
free(i);
}
XSetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s], None, CurrentTime);
W->systray.barwin->geo.w = 0;
infobar_elem_reinit(W->systray.infobar);
XSync(W->dpy, false);
}
struct _systray*
systray_find(Window win)
{
struct _systray *i;
if(!(W->flags & WMFS_SYSTRAY))
return NULL;
SLIST_FOREACH(i, &W->systray.head, next)
if(i->win == win)
return i;
return NULL;
}
int
systray_get_width(void)
{
int w = 1;
struct _systray *i;
SLIST_FOREACH(i, &W->systray.head, next)
w += i->geo.w + SYSTRAY_SPACING;
return w;
}
void
systray_update(void)
{
int x = 1;
struct _systray *i;
if(!(W->flags & WMFS_SYSTRAY))
return;
if(W->systray.redim)
{
W->systray.redim = false;
infobar_elem_reinit(W->systray.infobar);
}
SLIST_FOREACH(i, &W->systray.head, next)
{
XMapWindow(W->dpy, i->win);
XMoveResizeWindow(W->dpy, i->win, (i->geo.x = x), 0, i->geo.w, i->geo.h);
x += i->geo.w + SYSTRAY_SPACING;
}
}

20
src/systray.h Normal file
View File

@ -0,0 +1,20 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef SYSTRAY_H
#define SYSTRAY_H
#include "wmfs.h"
void systray_acquire(void);
void systray_add(Window win);
void systray_del(struct _systray *s);
void systray_state(struct _systray *s);
void systray_freeicons(void);
struct _systray *systray_find(Window win);
int systray_get_width(void);
void systray_update(void);
#endif /* SYSTRAY_H */

104
src/tag.c
View File

@ -22,7 +22,6 @@ tag_new(struct screen *s, char *name)
t = xcalloc(1, sizeof(struct tag));
t->screen = s;
t->name = xstrdup(name);
t->flags = 0;
t->id = 0;
t->sel = NULL;
@ -31,6 +30,11 @@ tag_new(struct screen *s, char *name)
if((l = TAILQ_LAST(&s->tags, tsub)))
t->id = l->id + 1;
if(!name || !strlen(name))
xasprintf(&t->name, "%d", t->id + 1);
else
t->name = xstrdup(name);
SLIST_INIT(&t->clients);
TAILQ_INIT(&t->sets);
@ -42,20 +46,31 @@ tag_new(struct screen *s, char *name)
void
tag_screen(struct screen *s, struct tag *t)
{
if(t == s->seltag)
struct client *c;
/* Return to the previous tag */
if(t == s->seltag && TAILQ_NEXT(TAILQ_FIRST(&s->tags), next))
t = t->prev;
if(!t)
t = TAILQ_FIRST(&s->tags);
/* Move clients which ignore tags */
SLIST_FOREACH(c, &W->h.client, next)
if (c->flags & CLIENT_IGNORE_TAG)
tag_client(t, c);
t->prev = s->seltag;
s->seltag = t;
clients_arrange_map();
/* Update focus */
if(!SLIST_EMPTY(&t->clients) && !(W->flags & WMFS_SCAN))
client_focus( client_tab_next(t->sel));
t->flags &= ~TAG_URGENT;
infobar_elem_screen_update(s, ElemTag);
ewmh_update_wmfs_props();
@ -71,7 +86,7 @@ tag_client(struct tag *t, struct client *c)
if(c->tag == t)
return;
if(!(c->flags & CLIENT_IGNORE_LAYOUT))
if(!(c->flags & (CLIENT_IGNORE_LAYOUT | CLIENT_FREE)))
layout_split_arrange_closed(c);
if(!(c->flags & CLIENT_REMOVEALL))
@ -87,7 +102,10 @@ tag_client(struct tag *t, struct client *c)
/* Client remove */
if(!t)
{
infobar_elem_screen_update(c->screen, ElemTag);
return;
}
c->prevtag = c->tag;
c->tag = t;
@ -95,16 +113,9 @@ tag_client(struct tag *t, struct client *c)
client_update_props(c, CPROP_LOC);
/*
* Insert in new tag list before
* layout_split_integrate, because of set historic.
*/
SLIST_INSERT_HEAD(&t->clients, c, tnext);
if(c->flags & CLIENT_IGNORE_LAYOUT)
c->flags ^= CLIENT_IGNORE_LAYOUT;
else if(!(c->flags & CLIENT_TABBED))
layout_split_integrate(c, t->sel);
infobar_elem_screen_update(c->screen, ElemTag);
if(c->flags & CLIENT_TABMASTER && c->prevtag)
{
@ -112,8 +123,13 @@ tag_client(struct tag *t, struct client *c)
SLIST_FOREACH(cc, &c->prevtag->clients, tnext)
if(cc->tabmaster == c)
{
cc->flags |= CLIENT_IGNORE_LAYOUT;
tag_client(t, cc);
}
}
layout_client(c);
if(t != c->screen->seltag || c->flags & CLIENT_TABBED)
client_unmap(c);
@ -154,7 +170,7 @@ uicb_tag_next(Uicb cmd)
if((t = TAILQ_NEXT(W->screen->seltag, next)))
tag_screen(W->screen, t);
else if( /* CIRCULAR OPTION */ 1)
else if(W->flags & WMFS_TAGCIRC)
tag_screen(W->screen, TAILQ_FIRST(&W->screen->tags));
}
@ -166,7 +182,7 @@ uicb_tag_prev(Uicb cmd)
if((t = TAILQ_PREV(W->screen->seltag, tsub, next)))
tag_screen(W->screen, t);
else if( /* CIRCULAR OPTION */ 1)
else if(W->flags & WMFS_TAGCIRC)
tag_screen(W->screen, TAILQ_LAST(&W->screen->tags, tsub));
}
@ -176,19 +192,29 @@ uicb_tag_client(Uicb cmd)
struct tag *t;
int id = ATOI(cmd);
if((t = tag_gb_id(W->screen, id)))
if(W->client && (t = tag_gb_id(W->screen, id)))
tag_client(t, W->client);
}
void
uicb_tag_client_and_set(Uicb cmd)
{
uicb_tag_client(cmd);
uicb_tag_set(cmd);
}
void
uicb_tag_move_client_next(Uicb cmd)
{
(void)cmd;
struct tag *t;
if(!W->client)
return;
if((t = TAILQ_NEXT(W->screen->seltag, next)))
tag_client(t, W->client);
else if( /* CIRCULAR OPTION */ 1)
else if(W->flags & WMFS_TAGCIRC)
tag_client(TAILQ_FIRST(&W->screen->tags), W->client);
}
@ -198,9 +224,12 @@ uicb_tag_move_client_prev(Uicb cmd)
(void)cmd;
struct tag *t;
if(!W->client)
return;
if((t = TAILQ_PREV(W->screen->seltag, tsub, next)))
tag_client(t, W->client);
else if( /* CIRCULAR OPTION */ 1)
else if(W->flags & WMFS_TAGCIRC)
tag_client(TAILQ_LAST(&W->screen->tags, tsub), W->client);
}
@ -218,6 +247,8 @@ uicb_tag_click(Uicb cmd)
static void
tag_remove(struct tag *t)
{
TAILQ_REMOVE(&t->screen->tags, t, next);
free(t->name);
layout_free_set(t);
@ -226,13 +257,46 @@ tag_remove(struct tag *t)
}
void
tag_free(struct screen *s)
uicb_tag_new(Uicb cmd)
{
struct tag *t;
struct screen *s = W->screen;
struct infobar *i;
TAILQ_FOREACH(t, &s->tags, next)
tag_new(s, (char*)cmd);
s->flags |= SCREEN_TAG_UPDATE;
SLIST_FOREACH(i, &s->infobars, next)
infobar_elem_reinit(i);
s->flags ^= SCREEN_TAG_UPDATE;
}
void
uicb_tag_del(Uicb cmd)
{
struct infobar *i;
struct tag *t = W->screen->seltag;
(void)cmd;
if(SLIST_EMPTY(&t->clients)
&& TAILQ_NEXT(TAILQ_FIRST(&W->screen->tags), next))
{
TAILQ_REMOVE(&s->tags, t, next);
tag_screen(W->screen, TAILQ_NEXT(t, next));
tag_remove(t);
W->screen->flags |= SCREEN_TAG_UPDATE;
SLIST_FOREACH(i, &W->screen->infobars, next)
infobar_elem_reinit(i);
W->screen->flags ^= SCREEN_TAG_UPDATE;
}
}
void
tag_free(struct screen *s)
{
while(!TAILQ_EMPTY(&s->tags))
tag_remove(TAILQ_FIRST(&s->tags));
}

View File

@ -8,7 +8,6 @@
#include "wmfs.h"
static inline struct tag*
tag_gb_id(struct screen *s, int id)
{
@ -30,9 +29,11 @@ void uicb_tag_set_with_name(Uicb cmd);
void uicb_tag_next(Uicb cmd);
void uicb_tag_prev(Uicb cmd);
void uicb_tag_client(Uicb cmd);
void uicb_tag_client_and_set(Uicb cmd);
void uicb_tag_move_client_next(Uicb cmd);
void uicb_tag_move_client_prev(Uicb cmd);
void uicb_tag_click(Uicb cmd);
void uicb_tag_new(Uicb cmd);
void uicb_tag_del(Uicb cmd);
#endif /* TAG_H */

View File

@ -46,6 +46,28 @@ xcalloc(size_t nmemb, size_t size)
return ret;
}
/** realloc with error support and size_t overflow check
* \param ptr old pointer
* \param nmemb number of objects
* \param size size of single object
* \return non null void pointer
*/
void *
xrealloc(void *ptr, size_t nmemb, size_t size)
{
void *ret;
if(SIZE_MAX / nmemb < size)
err(EXIT_FAILURE, "xrealloc(%p, %zu, %zu), "
"size_t overflow detected", ptr, nmemb, size);
if((ret = realloc(ptr, nmemb * size)) == NULL)
err(EXIT_FAILURE, "realloc(%p, %zu)", ptr, nmemb * size);
return ret;
}
/** asprintf wrapper
* \param strp target string
* \param fmt format
@ -108,7 +130,7 @@ spawn(const char *format, ...)
if(!(sh = getenv("SHELL")) || sh[0] != '/')
sh = "/bin/sh";
if((pid = fork()) == 0)
if(!(pid = fork()))
{
setsid();
if (execl(sh, sh, "-c", cmd, (char*)NULL) == -1)
@ -126,8 +148,8 @@ parse_args(char *str, char delim, char end, int narg, char *args[])
{
int i = 0;
for(args[0] = str; *str && *str != end && i < narg; ++str)
if(*str == delim)
for(args[0] = str; *str && (*str != end || *(str - 1) == '\\') && i < narg; ++str)
if(*str == delim && i < narg - 1)
{
*str = '\0';
args[++i] = ++str;

View File

@ -23,7 +23,7 @@
/* Insert at the end with SLIST */
#define SLIST_INSERT_TAIL(head, elem, field, prev) \
if(SLIST_EMPTY(head)) \
if(!prev) \
SLIST_INSERT_HEAD(head, elem, field); \
else \
SLIST_INSERT_AFTER(prev, elem, field);
@ -49,9 +49,12 @@
static inline Color
color_atoh(const char *col)
{
int shift = (col[0] == '#');
XColor xcolor;
return (Color)strtol(col + shift, NULL, 16);
if(!XAllocNamedColor(W->dpy, DefaultColormap(W->dpy, W->xscreen), col, &xcolor, &xcolor))
warnl("Error: cannot allocate color \"%s\".", col);
return xcolor.pixel;
}
static inline void
@ -63,6 +66,14 @@ swap_ptr(void **x, void **y)
*y = t;
}
static inline void
swap_int(int *x, int *y)
{
*y = *x ^ *y;
*x = *y ^ *x;
*y = *x ^ *y;
}
static inline enum position
str_to_position(char *str)
{
@ -78,6 +89,7 @@ str_to_position(char *str)
void *xmalloc(size_t nmemb, size_t size);
void *xcalloc(size_t nmemb, size_t size);
void *xrealloc(void *ptr, size_t nmemb, size_t size);
int xasprintf(char **strp, const char *fmt, ...);
char *xstrdup(const char *str);
pid_t spawn(const char *format, ...);

View File

@ -3,10 +3,17 @@
* For license, see COPYING.
*/
#include <string.h>
#include <getopt.h>
#include <signal.h>
#include <sys/wait.h>
#include <X11/keysym.h>
#include <X11/cursorfont.h>
#ifdef HAVE_IMLIB2
#include <Imlib2.h>
#endif /* HAVE_IMLIB2 */
#include "wmfs.h"
#include "event.h"
#include "ewmh.h"
@ -15,7 +22,8 @@
#include "util.h"
#include "config.h"
#include "client.h"
#include "fifo.h"
#include "layout.h"
#include "systray.h"
int
wmfs_error_handler(Display *d, XErrorEvent *event)
@ -153,6 +161,16 @@ wmfs_xinit(void)
* Barwin linked list
*/
SLIST_INIT(&W->h.barwin);
SLIST_INIT(&W->h.vbarwin);
/*
* Optional dep init
*/
#ifdef HAVE_IMLIB2
imlib_context_set_display(W->dpy);
imlib_context_set_visual(DefaultVisual(W->dpy, W->xscreen));
imlib_context_set_colormap(DefaultColormap(W->dpy, W->xscreen));
#endif /* HAVE_IMLIB2 */
W->flags |= WMFS_RUNNING;
}
@ -189,7 +207,7 @@ wmfs_scan(void)
int i, n, rf, nscreen = 0;
int tag = -1, screen = -1, flags = -1;
unsigned long ir, il;
long *ret, *tret;
long *ret = NULL, *tret = NULL;
bool getg = false;
XWindowAttributes wa;
Window usl, usl2, *w = NULL, tm, focus;
@ -203,7 +221,7 @@ wmfs_scan(void)
if(XGetWindowProperty(W->dpy, W->root, W->net_atom[wmfs_current_tag], 0, 32,
False, XA_CARDINAL, &rt, &rf, &ir, &il,
(unsigned char**)&tret)
== Success && ret)
== Success && tret)
{
nscreen = (int)ir;
}
@ -226,6 +244,15 @@ wmfs_scan(void)
if(!wa.override_redirect && wa.map_state == IsViewable)
{
if(ewmh_get_xembed_state(w[i]))
{
systray_add(w[i]);
continue;
}
if(ewmh_manage_window_type_desktop(w[i]))
continue;
if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_TAG"), 0, 32,
False, XA_CARDINAL, &rt, &rf, &ir, &il,
(unsigned char**)&ret)
@ -293,11 +320,16 @@ wmfs_scan(void)
if(getg)
c->flags |= CLIENT_IGNORE_LAYOUT;
client_map(c);
tag_client(tag_gb_id(c->screen, tag), c);
if(getg)
if(getg && tag <= TAILQ_LAST(&c->screen->tags, tsub)->id - 1)
client_moveresize(c, &g);
/* In a removed tag */
else
{
c->geo = g;
layout_client(c);
}
client_get_name(c);
}
@ -328,6 +360,10 @@ wmfs_scan(void)
if((fc = client_gb_win(focus)) && fc != W->client)
client_focus(fc);
SLIST_FOREACH(c, &W->h.client, next)
if(c->flags & CLIENT_TILED)
layout_fix_hole(c);
W->flags &= ~WMFS_SCAN;
if(tret)
@ -337,40 +373,27 @@ wmfs_scan(void)
XSync(W->dpy, false);
}
static inline void
wmfs_sigchld(void)
{
if(W->flags & WMFS_SIGCHLD)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
W->flags ^= WMFS_SIGCHLD;
}
}
static void
wmfs_loop(void)
{
XEvent ev;
int maxfd, fd = ConnectionNumber(W->dpy);
fd_set iset;
while(W->flags & WMFS_RUNNING)
while((W->flags & WMFS_RUNNING) && !XNextEvent(W->dpy, &ev))
{
maxfd = fd + 1;
FD_ZERO(&iset);
FD_SET(fd, &iset);
if(W->fifo.fd > 0)
{
maxfd += W->fifo.fd;
FD_SET(W->fifo.fd, &iset);
}
if(select(maxfd, &iset, NULL, NULL, NULL) > 0)
{
if(FD_ISSET(fd, &iset))
{
while((W->flags & WMFS_RUNNING) && XPending(W->dpy))
{
XNextEvent(W->dpy, &ev);
/* Manage SIGCHLD event here, X is not safe with it */
wmfs_sigchld();
EVENT_HANDLE(&ev);
}
}
else if(W->fifo.fd > 0 && FD_ISSET(W->fifo.fd, &iset))
fifo_read();
}
}
}
static inline void
@ -382,7 +405,6 @@ wmfs_init(void)
screen_init();
event_init();
config_init();
fifo_init();
}
void
@ -393,16 +415,10 @@ wmfs_quit(void)
struct theme *t;
struct client *c;
struct mousebind *m;
struct launcher *l;
/* Will free:
*
* Screens -> tags
* -> Infobars -> Elements
*/
ewmh_update_wmfs_props();
screen_free();
XFreeGC(W->dpy, W->rgc);
while(!SLIST_EMPTY(&W->h.client))
@ -410,29 +426,32 @@ wmfs_quit(void)
c = SLIST_FIRST(&W->h.client);
client_update_props(c, CPROP_LOC | CPROP_FLAG | CPROP_GEO);
c->flags |= (CLIENT_IGNORE_LAYOUT | CLIENT_REMOVEALL);
XMapWindow(W->dpy, c->win);
client_remove(c);
}
/* Will free:
*
* Screens -> tags
* -> Infobars -> Elements
*/
screen_free();
/* Conf stuffs */
while(!SLIST_EMPTY(&W->h.theme))
{
t = SLIST_FIRST(&W->h.theme);
SLIST_REMOVE_HEAD(&W->h.theme, next);
XFreeFontSet(W->dpy, t->font.fontset);
status_free_ctx(&t->tags_n_sl);
status_free_ctx(&t->tags_s_sl);
status_free_ctx(&t->tags_o_sl);
status_free_ctx(&t->tags_u_sl);
status_free_ctx(&t->client_n_sl);
status_free_ctx(&t->client_s_sl);
free(t);
}
while(!SLIST_EMPTY(&W->h.rule))
{
r = SLIST_FIRST(&W->h.rule);
SLIST_REMOVE_HEAD(&W->h.rule, next);
free(r->class);
free(r->instance);
free(r->role);
free(r->name);
free(r);
}
while(!SLIST_EMPTY(&W->h.keybind))
{
k = SLIST_FIRST(&W->h.keybind);
@ -449,11 +468,25 @@ wmfs_quit(void)
free(m);
}
/* FIFO stuffs */
if(W->fifo.fd > 0)
while(!SLIST_EMPTY(&W->h.launcher))
{
close(W->fifo.fd);
unlink(W->fifo.path);
l = SLIST_FIRST(&W->h.launcher);
SLIST_REMOVE_HEAD(&W->h.launcher, next);
free((void*)l->name);
free((void*)l->prompt);
free((void*)l->command);
free(l);
}
while(!SLIST_EMPTY(&W->h.rule))
{
r = SLIST_FIRST(&W->h.rule);
SLIST_REMOVE_HEAD(&W->h.rule, next);
free(r->class);
free(r->instance);
free(r->role);
free(r->name);
free(r);
}
/* close log */
@ -461,8 +494,6 @@ wmfs_quit(void)
fclose(W->log), W->log = NULL;
W->flags &= ~WMFS_RUNNING;
XCloseDisplay(W->dpy);
}
/** Reload WMFS binary
@ -484,41 +515,101 @@ uicb_quit(Uicb cmd)
W->flags &= ~WMFS_RUNNING;
}
static void
exec_uicb_function(Display *dpy, Window root, char *func, char *cmd)
{
Atom utf8s = XInternAtom(dpy, "UTF8_STRING", false);
XClientMessageEvent e = {
.type = ClientMessage,
.message_type = XInternAtom(dpy, "_WMFS_FUNCTION", false),
.window = root,
.format = 32,
.data.l[4] = true
};
XChangeProperty(dpy,root, XInternAtom(dpy, "_WMFS_FUNCTION", false), utf8s,
8, PropModeReplace, (unsigned char*)func, strlen(func));
if(!cmd)
cmd = "";
XChangeProperty(dpy, root, XInternAtom(dpy, "_WMFS_CMD", false), utf8s,
8, PropModeReplace, (unsigned char*)cmd, strlen(cmd));
XSendEvent(dpy, root, false, StructureNotifyMask, (XEvent*)&e);
XSync(dpy, False);
}
static void
signal_handle(int sig)
{
switch (sig)
{
case SIGQUIT:
case SIGTERM:
W->flags &= ~WMFS_RUNNING;
break;
case SIGCHLD:
W->flags |= WMFS_SIGCHLD;
break;
}
}
int
main(int argc, char **argv)
{
int i;
bool r;
Display *dpy;
char path[MAX_PATH_LEN] = { 0 };
struct sigaction sa;
(void)argc;
sprintf(path, "%s/"CONFIG_DEFAULT_PATH, getenv("HOME"));
/* Opt */
while((i = getopt(argc, argv, "hvC:c:")) != -1)
{
switch(i)
{
default:
case 'h':
printf("usage: %s [-hv] [-c <func> <cmd] [-C <file>]\n"
" -h Show this page\n"
" -v Show WMFS version\n"
" -c <func> <cmd> Execute a specified UICB function\n"
" -C <file> Launch WMFS with a specified configuration file\n", argv[0]);
exit(EXIT_SUCCESS);
break;
case 'v':
printf("wmfs("WMFS_VERSION") 2 beta\n");
exit(EXIT_SUCCESS);
break;
case 'c':
if(!(dpy = XOpenDisplay(NULL)))
{
fprintf(stderr, "%s: Can't open X server\n", argv[0]);
exit(EXIT_FAILURE);
}
exec_uicb_function(dpy, DefaultRootWindow(dpy), optarg, argv[optind]);
XCloseDisplay(dpy);
exit(EXIT_SUCCESS);
break;
case 'C':
strncpy(path, optarg, MAX_PATH_LEN);
break;
}
}
W = (struct wmfs*)xcalloc(1, sizeof(struct wmfs));
/* Default path ~/.config/wmfs/wmfsrc */
sprintf(W->confpath, "%s/"CONFIG_DEFAULT_PATH, getenv("HOME"));
/* Opt */
while((i = getopt(argc, argv, "hvC:")) != -1)
{
switch(i)
{
case 'h':
printf("usage: %s [-hv] [-C <file>]\n"
" -h Show this page\n"
" -v Show WMFS version\n"
" -C <file> Launch WMFS with a specified configuration file\n", argv[0]);
free(W);
exit(EXIT_SUCCESS);
break;
case 'v':
printf("wmfs("WMFS_VERSION") 2 beta\n");
free(W);
exit(EXIT_SUCCESS);
break;
case 'C':
strncpy(W->confpath, optarg, sizeof(W->confpath));
break;
}
}
W->confpath = path;
/* Get X display */
if(!(W->dpy = XOpenDisplay(NULL)))
@ -527,6 +618,14 @@ main(int argc, char **argv)
exit(EXIT_FAILURE);
}
/* Set signal handler */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = signal_handle;
sigemptyset(&sa.sa_mask);
sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGCHLD, &sa, NULL);
/* Core */
wmfs_init();
wmfs_scan();
@ -539,5 +638,7 @@ main(int argc, char **argv)
if(r)
execvp(argv[0], argv);
XCloseDisplay(W->dpy);
return 1;
}

View File

@ -92,26 +92,51 @@ struct barwin
Color fg, bg;
void *ptr; /* Special cases */
SLIST_HEAD(mbhead, mousebind) mousebinds;
SLIST_HEAD(, mousebind) statusmousebinds;
SLIST_ENTRY(barwin) next; /* global barwin */
SLIST_ENTRY(barwin) enext; /* element barwin */
SLIST_ENTRY(barwin) vnext; /* volatile barwin */
};
struct status_seq
{
struct geo geo;
enum position align;
int data[4];
char type;
char *str;
Color color;
Color color, color2;
SLIST_HEAD(, mousebind) mousebinds;
SLIST_ENTRY(status_seq) next;
};
struct status_ctx
{
struct barwin *barwin;
struct theme *theme;
#define STATUS_BLOCK_REFRESH 0x01
Flags flags;
char *status;
bool update;
SLIST_HEAD(, status_gcache) gcache;
SLIST_HEAD(, status_seq) statushead;
};
struct status_gcache
{
char *name;
int *datas;
int ndata;
SLIST_ENTRY(status_gcache) next;
};
struct element
{
struct geo geo;
struct infobar *infobar;
struct status_ctx *statusctx;
int type;
char *data;
enum position align;
void (*func_init)(struct element *e);
void (*func_update)(struct element *e);
@ -125,12 +150,11 @@ struct infobar
struct geo geo;
struct screen *screen;
struct theme *theme;
enum barpos pos;
struct status_ctx statusctx;
enum barpos opos, pos;
char *elemorder;
char *name;
char *status;
TAILQ_HEAD(esub, element) elements;
SLIST_HEAD(, status_seq) statushead;
SLIST_ENTRY(infobar) next;
};
@ -138,8 +162,9 @@ struct screen
{
struct geo geo, ugeo;
struct tag *seltag;
#define SCREEN_TAG_UPDATE 0x01
Flags flags;
int id;
Flags elemupdate;
TAILQ_HEAD(tsub, tag) tags;
SLIST_HEAD(, infobar) infobars;
SLIST_ENTRY(screen) next;
@ -153,8 +178,11 @@ struct tag
struct client *sel;
struct client *prevsel;
struct tag *prev;
struct status_ctx statusctx;
char *name;
int id;
#define TAG_URGENT 0x01
#define TAG_IGNORE_ENTER 0x02
Flags flags;
SLIST_HEAD(, client) clients;
TAILQ_HEAD(ssub, layout_set) sets;
@ -185,6 +213,10 @@ struct client
#define CLIENT_REMOVEALL 0x200
#define CLIENT_MAPPED 0x400
#define CLIENT_FULLSCREEN 0x800
#define CLIENT_FREE 0x1000
#define CLIENT_TILED 0x2000
#define CLIENT_MOUSE 0x4000
#define CLIENT_IGNORE_TAG 0x8000
Flags flags;
Window win, frame, tmp;
SLIST_ENTRY(client) next; /* Global list */
@ -235,12 +267,14 @@ struct theme
int bars_width;
/* struct elements */
struct colpair tags_n, tags_s; /* normal / selected */
struct colpair tags_n, tags_s, tags_o, tags_u; /* normal / selected / occupied */
struct status_ctx tags_n_sl, tags_s_sl, tags_o_sl, tags_u_sl; /* status line */
int tags_border_width;
Color tags_border_col;
/* client / frame */
struct colpair client_n, client_s;
struct status_ctx client_n_sl, client_s_sl, client_f_sl;
Color frame_bg;
int client_titlebar_width;
int client_border_width;
@ -257,12 +291,38 @@ struct rule
char *name;
int tag, screen;
#define RULE_FREE 0x01
#define RULE_MAX 0x02
#define RULE_TAB 0x02
#define RULE_IGNORE_TAG 0x04
Flags flags;
SLIST_ENTRY(rule) next;
};
struct launcher
{
char *name;
char *prompt;
char *command;
#define HISTOLEN 64
char histo[HISTOLEN][256];
int nhisto;
int width;
SLIST_ENTRY(launcher) next;
};
struct launcher_ccache
{
char *start;
char **namelist;
size_t hits;
};
struct _systray
{
struct geo geo;
Window win;
SLIST_ENTRY(_systray) next;
};
#define MAX_PATH_LEN 8192
struct wmfs
@ -273,23 +333,30 @@ struct wmfs
int xscreen, xdepth;
int xmaxw, xmaxh;
int nscreen;
unsigned int client_mod;
Flags numlockmask;
#define WMFS_SCAN 0x01
#define WMFS_RUNNING 0x02
#define WMFS_RELOAD 0x04
#define WMFS_SCAN 0x001
#define WMFS_RUNNING 0x002
#define WMFS_RELOAD 0x004
#define WMFS_SYSTRAY 0x008
#define WMFS_LOG 0x010
#define WMFS_LAUNCHER 0x020
#define WMFS_SIGCHLD 0x040
#define WMFS_TABNOC 0x080 /* tab next opened client */
#define WMFS_TAGCIRC 0x100 /* tab_next on last tag -> go to first tag / tab_prev on first tag -> go to last tag */
#define WMFS_AUTOFOCUS 0x200
Flags flags;
GC gc, rgc;
Atom *net_atom;
char **argv;
char confpath[MAX_PATH_LEN];
char *confpath;
struct barwin *last_clicked_barwin;
struct theme *ctheme;
#define CFOCUS_ENTER 0x01
#define CFOCUS_CLICK 0x02
Flags cfocus; /* Focus configuration, can be set to 0, CFOCUS_ENTER or CFOCUS_CLICK*/
/* FIFO stuffs */
struct
{
char *path;
int fd;
} fifo;
int padding;
/* Log file */
FILE *log;
@ -304,6 +371,8 @@ struct wmfs
SLIST_HEAD(, theme) theme;
SLIST_HEAD(, rule) rule;
SLIST_HEAD(, mousebind) mousebind;
SLIST_HEAD(, launcher) launcher;
SLIST_HEAD(, barwin) vbarwin;
} h;
/*
@ -318,6 +387,19 @@ struct wmfs
struct mbhead root;
} tmp_head;
/*
* Because there is only one systray per display,
* set struct there
*/
struct
{
struct barwin *barwin;
struct infobar *infobar;
bool redim;
Window win;
SLIST_HEAD(, _systray) head;
} systray;
/*
* Selected screen, client
*/

788
wmfs.1 Normal file
View File

@ -0,0 +1,788 @@
.\" title: wmfs
.\" dev: xorg62
.\" man: arpinux
.\"
.TH "WMFS" "1" "2012/05/02" "wmfs" "manual of wmfs"
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.SH "NAME"
wmfs \- Window Manager From Scratch
.SH "SYNOPSIS"
\fBwmfs\fR [\fB\-hv\fR] [\fB\-C <file>\fR] [\fB\-c <uicb_function> <cmd>\fR]
.sp
.SH "DESCRIPTION"
\fBWMFS\fR is a lightweight and highly configurable tiling window manager for X written in C\&.
.sp
.SH "OPTIONS"
.PP
\fB\-C <file>\fR
.RS 4
Load a configuration file\&.
.RE
.PP
\fB\-c <uicb_function> <cmd>\fR
.RS 4
Execute an uicb function to control WMFS\&.
.RE
.PP
\fB\-v\fR
.RS 4
Print version information to standard output, then exit\&.
.RE
.PP
\fB\-h\fR
.RS 4
Print help information, then exit\&.
.RE
.SH "DEFAULT KEY BINDINGS"
.PP
\fBControl\-Alt + r\fR
.RS 4
Reload WMFS binary
.RE
.PP
\fBSuper + Return\fR
.RS 4
Run a terminal (urxvt by default)
.RE
.PP
\fBSuper + q\fR
.RS 4
Quit the selected client
.RE
.PP
\fBControl\-Alt + q\fR
.RS 4
Exit WMFS
.RE
.PP
\fBSuper + f \fR
.RS 4
Toggle free the selected client
.RE
.PP
\fBSuper + Shift + f \fR
.RS 4
Toggle ignore_tag the selected client
.RE
.PP
\fBSuper + Shift + h \fR
.RS 4
Toggle infobar visibility
.RE
.PP
\fBAlt + Tab\fR
.RS 4
Give the focus to the next client
.RE
.PP
\fBAlt\-Shift + Tab\fR
.RS 4
Give the focus to the previous client
.RE
.PP
\fBAlt + h\fR
.RS 4
Give the focus to the client on the left
.RE
.PP
\fBAlt + l\fR
.RS 4
Give the focus to the client on the right
.RE
.PP
\fBAlt + k\fR
.RS 4
Give the focus to the client on the top
.RE
.PP
\fBAlt + j\fR
.RS 4
Give the focus to the client on the bottom
.RE
.PP
\fBSuper + Tab\fR
.RS 4
Give the focus to the next tabbed client
.RE
.PP
\fBSuper\-Shift + Tab\fR
.RS 4
Give the focus to the previous tabbed client
.RE
.PP
\fBControl\-Shift + h\fR
.RS 4
Swap with the client on the left
.RE
.PP
\fBControl\-Shift + l\fR
.RS 4
Swap with the client on the right
.RE
.PP
\fBControl\-Shift + k\fR
.RS 4
Swap with the client on the top
.RE
.PP
\fBControl\-Shift + j\fR
.RS 4
Swap with the client on the bottom
.RE
.PP
\fBAlt\-Shift + h\fR
.RS 4
Tab in the client on the left
.RE
.PP
\fBAlt\-Shift + l\fR
.RS 4
Tab in the client on the right
.RE
.PP
\fBAlt\-Shift + k\fR
.RS 4
Tab in the client on the top
.RE
.PP
\fBAlt\-Shift + j\fR
.RS 4
Tab in the client on the bottom
.RE
.PP
\fBAlt\-Shift + u\fR
.RS 4
Untab the client
.RE
.PP
\fBSuper + h\fR
.RS 4
Increase the client to the left
.RE
.PP
\fBSuper + l\fR
.RS 4
Decrease the client from the left
.RE
.PP
\fBSuper + k\fR
.RS 4
Increase the client to the top
.RE
.PP
\fBSuper + j\fR
.RS 4
Decrease the client from the top
.RE
.PP
\fBSuper\-Control + h\fR
.RS 4
Decrease the client from the right
.RE
.PP
\fBSuper\-Control + l\fR
.RS 4
Increase the client to the right
.RE
.PP
\fBSuper\-Control + k\fR
.RS 4
Decrease the client from the bottom
.RE
.PP
\fBSuper\-Control + j\fR
.RS 4
Increase the client to the bottom
.RE
.PP
\fBControl + Right\fR
.RS 4
Next tag
.RE
.PP
\fBControl + Left\fR
.RS 4
Previous tag
.RE
.PP
\fBControl + Up\fR
.RS 4
Next screen
.RE
.PP
\fBControl + Down\fR
.RS 4
Previous screen
.RE
.PP
\fBSuper + m\fR
.RS 4
Vertical mirror layout
.RE
.PP
\fBSuper\-Shift + m\fR
.RS 4
Horizontal mirror layout
.RE
.PP
\fBSuper + r\fR
.RS 4
Rotate layout right
.RE
.PP
\fBSuper\-Shift + r\fR
.RS 4
Rotate layout left
.RE
.PP
\fBSuper\-Control\-Alt + h\fR
.RS 4
Integrate client in left layout
.RE
.PP
\fBSuper\-Control\-Alt + j\fR
.RS 4
Integrate client in bottom layout
.RE
.PP
\fBSuper\-Control\-Alt + k\fR
.RS 4
Integrate client in top layout
.RE
.PP
\fBSuper\-Control\-Alt + l\fR
.RS 4
Integrate client in right layout
.RE
.PP
\fBSuper + o\fR
.RS 4
Restore previous layout
.RE
.PP
\fBSuper\-Shift + o\fR
.RS 4
Restore next layout
.RE
.PP
\fBSuper + p\fR
.RS 4
Display a launcher in the statusbar to run an unix command\fR
.RE
.PP
\fBSuper + F[1\&.\&.9]\fR
.RS 4
Change tag view
.RE
.PP
\fBSuper\-Shift + F[1\&.\&.9]\fR
.RS 4
Transfert the selected client to the wanted tag
.RE
.PP
\fBSuper + -\fR
.RS 4
Delete current tag\fR
.RE
.PP
\fBSuper\-Shift + -\fR
.RS 4
Add current tag\fR
.RE
.SH "CONFIGURATION"
WMFS is configured by \fI$HOME/\&.config/wmfs/wmfsrc\fR\&.
.RE
.PP
\fB\ include:\fR
wmfsrc supports ”@include” to split configuration file by section\&.
.RS 2
\fB\ Usage:\fR "@include ~/.config/wmfs/wmfs_themes"\&.
.RE
.PP
\fB\ [themes]\fR
wmfsrc supports themes for client and statusbar\&.
.RS 2
\fB Misc\fR
.RS 2
\fB\ name:\fR
theme name, will be used in next sections\&.
.PP
\fB\ font:\fR
theme font in XLFD format\&.
.PP
.RE
\fB\ Bars\fR
.RS 2
\fB\ bars_width:\fR
bar height in pixels\&.
.PP
\fB\ bars_fg/bg:\fR
statusbar text/background color\&.
.PP
.RE
\fB\ Tags\fR
.RS 2
\fB\ tags_normal_fg/bg:\fR
normal tag text/button color\&.
.PP
\fB\ tags_normal_statusline:\fR
normal tag statusline\&.
.PP
\fB\ tags_sel_fg/bg:\fR
selected tag text/button color\&.
.PP
\fB\ tags_sel_statusline:\fR
selected tag statusline\&.
.PP
\fB\ tags_occupied_fg/bg:\fR
occupied tag text/button color\&.
.PP
\fB\ tags_occupied_statusline:\fR
occupied tag statusline\&.
.PP
\fB\ tags_urgent_fg/bg:\fR
urgent tag text/button color\&.
.PP
\fB\ tags_urgent_statusline:\fR
urgent tag statusline\&.
.PP
\fB\ tags_border_color:\fR
tag button border color\&.
.PP
\fB\ tags_border_width:\fR
tag button border width\&.
.PP
.RE
\fB\ Clients\fR
.RS 2
\fB\ client_normal_fg/bg:\fR
normal client titlebar text/background color\&.
.PP
\fB\ client_normal_statusline:\fR
normal client statusline\&.
.PP
\fB\ client_sel_fg/bg:\fR
selected client titlebar text/background color\&.
.PP
\fB\ client_sel_statusline:\fR
selected client statusline\&.
.PP
\fB\ frame_bg:\fR
client border color\&.
.PP
\fB\ client_titlebar_width:\fR
client titlebar height in pixels\&.
.PP
\fB\ client_border_width:\fR
client border height in pixels\&.
.RE
.PP
.RE
\fB\ [bars]\fR
.RS 2
\fB\ position:\fR
statusbar position on screen (0=Top; 1=Bottom, 2=Hide)\&.
.PP
\fB\ screen:\fR
screen to display statusbar (start ar 0), set to\fB -1\fR to display on every screen\&.
.PP
\fB\ elements:\fR
ordered statusbar elements t=Tags, s=Statustext, y=Systray, l=Launcher\&.
.PP
\fB\ theme:\fR
names of the statusbar theme\&.
.RE
.PP
.RE
\fB\ [tags]\fR
.RS 2
\fB\ circular:\fR
enable tag wrapping. default is true\&.
.PP
\fB\ screen:\fR
screen to display tag. use no screen option or screen =\fB -1\fR to set tag on each screen\&.
.PP
\fB\ name:\fR
display tagname\&.
.PP
\fB\ statusline:\fR
draw a custom statusline in the specific tag (can display any sequences)\&.
.PP
\fB\ mousebinds:\fR
mouse actions on the tag buttons\&.
.RE
.PP
.RE
\fB\ [client]\fR
.RS 2
\fB\ theme:\fR
apply theme to client by default\&.
.PP
\fB\ key_modifier:\fR
key modifier to perform actions on clients\&.
.PP
\fB\ focus:\fR
select the focus mouse options; enter=focus follow mouse, click=click to focus, everything-else=disable focus mouse support\&.
.PP
\fB\ mousebinds:\fR
mouse actions on client\&.
.PP
\fB\ padding:\fR
enable padding between clients. default is 0\&.
.PP
\fB\ autofocus:\fR
give focus to new created clients. default is false\&.
.RE
.PP
.RE
\fB\ [rules]\fR
specific rules for clients: to identify an application, use xprop\&.
.RS 2
\fB\ instance:\fR
first part of WM_CLASS\&.
.PP
\fB\ class:\fR
second part of WM_CLASS\&.
.PP
\fB\ role:\fR
WM_WINDOW_ROLE\&.
.PP
\fB\ name:\fR
_NET_WM_NAME\&.
.PP
\fB\ theme:\fR
apply theme to client\&.
.PP
\fB\ tag:\fR
specify a tag to display client (start at 0)\&.
.PP
\fB\ screen:\fR
display client on a specific screen\&.
.PP
\fB\ free:\fR
client in auto-free mode (true/false)\&.
.PP
\fB\ tab:\fR
open client in a tab (true/false)\&.
.PP
\fB\ ignore_tag:\fR
specify to client to ignore tags (client is displayed on every tag)\&.
.RE
.PP
.RE
\fB\ [launchers]\fR
.RS 2
\fB\ name:\fR
launcher-name, will be used in the [keys] section\&.
.PP
\fB\ prompt:\fR
display text at the beginning of the prompt\&.
.PP
\fB\ command:\fR
command used by the launcher. can be an uicb function or an uicb function + extension\&.
.RE
.PP
.RE
\fB\ [keys]\fR
.RS 2
each line is contained within\fB\ [key]...[/key]\fR
.PP
\fB\ mod:\fR
key modifier (Alt, Control, Shift, Super)\&.
.PP
\fB\ key:\fR
key to press, you can identify it with "xev"\&.
.PP
\fB\ func:\fR
uicb function to launch\&.
.PP
\fB\ cmd:\fR
if\fB\ func = "spawn"\fR set the external command to launch\&.
.sp
.SH "STATUS"
statusbars, tags, surfaces and titlebars support sequences to display text, images bars and graphs through the\fB\ wmfs -c status\fR command.
.PP
\fB\ Syntax\fR
.PP
.RS 4
\fB\ position:\fR “left/right” (relative) or “x;y” (absolute)\&.
.PP
\fB\ dimension:\fR “ww;hh” for width;height of the rectangle or the image, to display an image at its original size, set it to “0;0”\&.
.PP
\fB\ color:\fR ”#rrggbb”\&.
.PP
\fB\ imagepath:\fR absolute path for the image\&.
.PP
\fB\ border:\fR width of the progressbar border in pixels\&.
.PP
\fB\ curser:\fR width of the curser in the positionbar\&.
.PP
\fB\ value:\fR a variable, to draw progressbar\&.
.PP
\fB\ valuemax:\fR maximum value of the value used in the progressbar\&.
.RE
.PP
\fB\ basic usage:\fR
wmfs -c status "<barname> TEXT visible on 'barname'"\&.
.PP
\fB\ display colors:\fR
wmfs -c status "<barname> ^s[<position>;<color>;<text>]"\&.
.PP
\fB\ display rectangles:\fR
wmfs -c status "<barname> ^R[<position>;<dimensions>;<color>]"\&.
.PP
\fB\ display images:\fR
wmfs -c status "<barname> ^i[<position>;<dimensions>;<imagepath>]"\&.
.PP
\fB\ display progressbars:\fR
wmfs -c status "<barname> ^p[<position>;<dimensions>;<border>;<value>;<valuemax>;<bgcolor>;<fgcolor>]"\&.
.PP
\fB\ display positionbars:\fR
wmfs -c status "<barname> ^P[<position>;<dimensions>;<curser>;<value>;<valuemax>;<bgcolor>;<fgcolor>]"\&.
.PP
\fB\ display graph:\fR
wmfs -c status "<barname> ^g[<position>;<dimensions>;<value>;<valuemax>;<bgcolor>;<fgcolor>;<name>]"\&.
.RE
.PP
\fB\ mousebinds:\fR
sequences supports mousebinds with format\fB\ (<key>;<uicb-function>)\fR or\fB\ (<key>;<spawn>;<command>)\fR
.RE
.PP
\fB\ surfaces:\fR
you can display popups from the statusbar with the mousebind\fB\ (<key>;status_surface;<position>,<dimension>,<color> <datas>)\fR
.PP
.sp
.SH "UICB Functions"
UICB functions list. for “User Interface Call Backs”\&.
.PP
\fB\ usage in the wmfsrc:\fR func = "tag_next"\fB\ or\fR func = "spawn" cmd = "urxvt -e vim"\&.
.RE
\fB\ usage in the status.sh:\fR wmfs -c status "<barname> ^s[<position>;<color>;next](1;tag_next)"\&.
.RE
\fB\ usage in your terminal:\fR wmfs -c tag_next\&.
.PP
\fB\ spawn\fR
.RS 4
launch a command. ex: func = "spawn" cmd = "urxvtc -e screen irssi"\&.
.RE
.PP
\fB\ quit\fR
.RS 4
quit wmfs\&.
.RE
.PP
\fB\ reload\fR
.RS 4
reload wmfs\&.
.RE
.PP
\fB\ tag_set\fR
.RS 4
set tag by number\&.
.RE
.PP
\fB\ tag\fR
.RS 4
set tag by name\&.
.RE
.PP
\fB\ tag_next/prev\fR
.RS 4
set next/previous tag\&.
.RE
.PP
\fB\ tag_client\fR
.RS 4
tag the client\&.
.RE
.PP
\fB\ tag_client_and_set\fR
.RS 4
teg the client and set the tag\&.
.RE
.PP
\fB\ tag_move_client_next/prev\fR
.RS 4
tag the client with next/previous tag\&.
.RE
.PP
\fB\ tag_click\fR
.RS 4
display tag with a clic on tag button\&.
.RE
.PP
\fB\ tag_new/del\fR
.RS 4
add/delete a tag\&.
.RE
.PP
\fB infobar_toggle_hide\fR
.RS 4
toggle specific infobar visibility (infobar_name as cmd)\&.
.RE
.PP
\fB\ layout_vmirror\fR
.RS 4
vertical mirror tiling\&.
.RE
.PP
\fB\ layout_hmirror\fR
.RS 4
horizontal mirror tiling\&.
.RE
.PP
\fB\ layout_rotate_left\fR
.RS 4
tiling rotate anti/clockwise\&.
.RE
.PP
\fB\ layout_prev_set\fR
.RS 4
back to previous set layout\&.
.RE
.PP
\fB\ layout_next_set\fR
.RS 4
go to next set layout\&.
.RE
.PP
\fB\ layout_integrate_left/right/top/bottom\fR
.RS 4
client integration in the client zone by direction\&.
.RE
.PP
\fB\ client_close\fR
.RS 4
close the client\&.
.RE
.PP
\fB\ client_resize_right/left/top/bottom\fR
.RS 4
resize client with direction\&.
.RE
.PP
\fB\ client_focus_right/left/top/bottom\fR
.RS 4
focus client with direction\&.
.RE
.PP
\fB\ client_tab_right/left/top/bottom\fR
.RS 4
tab client with direction\&.
.RE
.PP
\fB\ client_swap_right/left/top/bottom\fR
.RS 4
swap client with direction\&.
.RE
.PP
\fB\ client_focus_next/prev\fR
.RS 4
move focus to the next/previous client\&.
.RE
.PP
\fB\ client_swap_next/prev\fR
.RS 4
swap with the next/previous client\&.
.RE
.PP
\fB\ client_untab\fR
.RS 4
untab the client\&.
.RE
.PP
\fB\ client_focus_next_tab\fR
.RS 4
move focus to next tab-client\&.
.RE
.PP
\fB\ client_focus_prev_tab\fR
.RS 4
move focus to previous tab-client\&.
.RE
.PP
\fB\ client_focus_click\fR
.RS 4
give focus to client with a clic\&.
.RE
.PP
\fB\ client_toggle_free\fR
.RS 4
toggle free the selected client\&.
.RE
.PP
\fB\ client_toggle_ignore_tag\fR
.RS 4
toggle ignore_tag the selected client\&.
.RE
.PP
\fB\ client_tab_next_opened\fR
.RS 4
open the client in a tab\&.
.RE
.PP
\fB\ status\fR
.RS 4
display the argument text in the statusbar\&.
.RE
.PP
\fB\ status_surface\fR
.RS 4
display a surface. can contain sequences\&.
.RE
.PP
\fB\ mouse_resize\fR
.RS 4
resize the client\&.
.RE
.PP
\fB\ mouse_move\fR
.RS 4
move the client\&.
.RE
.PP
\fB\ mouse_swap\fR
.RS 4
swap the client\&.
.RE
.PP
\fB\ mouse_tab\fR
.RS 4
tab the client\&.
.RE
.PP
\fB\ screen_next/prev\fR
.RS 4
go to next/previous screen\&.
.RE
.PP
\fB\ screen_move_client_next/prev\fR
.RS 4
move the client to next/previous screen\&.
.RE
.PP
\fB\ launcher\fR
.RS 4
native prompt. ex:\fB\ func = "launcher" cmd = "exec"\fR display the “exec” launcher\&.
.RE
.PP
.sp
.SH "BUGS"
WMFS isn\'t stable for now\&. So it certainly contains some bugs\&.
.sp
.SH "AUTHOR"
Martin Duquesnoy <\fIxorg62@gmail\&.com\fR\&[1]>\&.
.sp
.SH "WWW"
Main site: \fIhttps://github\&.com/xorg62/wmfs\fR
.PP
Wiki: \fIhttps://github\&.com/xorg62/wmfs/wiki\fR
.PP
Bug tracker: \fIhttps://github\&.com/xorg62/wmfs/issues\fR
.sp
.SH "COPYING"
WMFS is under the BSD license\&. See COPYING for more information\&.
.RE

7
wmfs.desktop Normal file
View File

@ -0,0 +1,7 @@
[Desktop Entry]
Encoding=UTF-8
Type=Application
Name=wmfs
Comment=Window Manager From Scratch
TryExec=wmfs
Exec=wmfs

View File

@ -1,52 +0,0 @@
" Vim syntax file
" Language: WMFS Configuration file
" Maintainer: David Delassus <david.jose.delassus@gmail.com>
" Latest Revision: 17 October 2011
if exists("b:current_syntax")
finish
endif
syn case ignore
" Keywords
syn keyword wmfsBlockTheme font
syn keyword wmfsBlockThemeBars bars_width bars_fg bars_bg
syn keyword wmfsBlockThemeTags tags_normal_fg tags_normal_bg tags_sel_fg tags_sel_bg tags_border_color tags_border_width
syn keyword wmfsBlockThemeClient client_normal_fg client_normal_bg client_sel_fg client_sel_bg frame_bg client_titlebar_width client_border_width
syn keyword wmfsBlockBar position screen elements theme
syn keyword wmfsBlockTag screen name
syn keyword wmfsBlockKey mod key func cmd
syn keyword wmfsTodo contained TODO FIXME XXX NOTE
" Matches
syn match wmfsNumber /\S\@<!\d\+\(\.\d\+\)\?\(\S\@!\|}\@=\)/ nextgroup=wmfsNumber
syn match wmfsNumber '\d\+' contained display
syn match wmfsNumber '[-+]\d\+' contained display
" Regions
syn region wmfsComment start="#" end="$" contains=wmfsTodo
syn region wmfsString start='"' end='"' contains=CONTAINED
syn region wmfsSection start="\[" end="\]"
syn region wmfsList start="{" end="}" contains=wmfsNumber,wmfsString
let b:current_syntax = "wmfs"
hi def link wmfsTodo Todo
hi def link wmfsComment Comment
hi def link wmfsSection Statement
hi def link wmfsList Statement
hi def link wmfsNumber Number
hi def link wmfsString String
hi def link wmfsBlockTheme Identifier
hi def link wmfsBlockThemeBars Identifier
hi def link wmfsBlockThemeTags Identifier
hi def link wmfsBlockThemeClient Identifier
hi def link wmfsBlockBar Identifier
hi def link wmfsBlockTag Identifier
hi def link wmfsBlockKey Identifier

85
wmfsrc
View File

@ -22,16 +22,34 @@
# Element tags
tags_normal_fg = "#AABBAA"
tags_normal_bg = "#223322"
# tags_normal_statusline = ""
tags_sel_fg = "#223322"
tags_sel_bg = "#AABBAA"
# tags_sel_statusline = ""
tags_occupied_fg = "#AABBAA"
tags_occupied_bg = "#445544"
tags_occupied_statusline = "\R[0;0;100;1;#AABBAA]"
tags_urgent_fg = "#223322"
tags_urgent_bg = "#CC5544"
# tags_urgent_statusline = ""
tags_border_color = "#112211"
tags_border_width = 1
# Frame / Client
client_normal_fg = "#AABBAA"
client_normal_bg = "#223322"
client_normal_statusline = "\s[3;9;#121212;x] \s[2;8;#ff0000;x](1;client_close)"
client_sel_fg = "#223322"
client_sel_bg = "#AABBAA"
client_sel_statusline = "\s[3;9;#121212;x] \s[2;8;#ff0000;x](1;client_close)"
# client_free_statusline = ""
frame_bg = "#555555"
client_titlebar_width = 12
client_border_width = 1
@ -52,11 +70,13 @@
#
# t Tags
# s Statustext (will take available space)
# y Systray (can be set only ONE time among all element)
# l Launcher (will be expended at launcher use)
[bar]
position = 0
screen = 0
elements = "ts" # element order in bar
elements = "tlsy" # element order in bar
theme = "default"
[/bar]
@ -71,10 +91,14 @@
[tags]
# Tag wrapping navigation
circular = false
# Use no screen option or screen = -1 to set tag on each screen
[tag]
screen = -1
name = "1"
# statusline=""
[/tag]
[tag] name = "2" [/tag]
@ -94,16 +118,34 @@
[client]
# Padding between clients (default: 0) :
#padding = 75
# Give focus to new created client (default = false)
autofocus = false
theme = "default"
key_modifier = "Super"
# Focus type:
# enter : focus follow mouse (default)
# click : click to focus
# everything-else : disable mouse focus support
focus = enter
[mouse] button = "1" func = "client_focus_click" [/mouse]
[mouse] button = "1" func = "mouse_swap" [/mouse]
[mouse] button = "2" func = "mouse_tab" [/mouse]
[mouse] button = "3" func = "mouse_resize" [/mouse]
[mouse] button = "4" func = "client_focus_next_tab" [/mouse]
[mouse] button = "5" func = "client_focus_prev_tab" [/mouse]
[/client]
[rules]
[rule]
# use instance = "*" for a all-clients rule
instance = "chromium"
# role = ""
@ -114,12 +156,28 @@
screen = 0
free = false
max = false
tab = false
ignore_tag = false
[/rule]
[/rules]
[launchers]
# command can be an uicb function or an uicb function + extension (see example)
[launcher]
name = "exec"
prompt = "Run:"
# Example of uicb + ext:
# command = "spawn xterm -e"
command = "spawn"
width = 150
[/launcher]
[/launchers]
[keys]
[key] mod = {"Super"} key = "Return" func = "spawn" cmd = "urxvt || xterm" [/key]
@ -146,6 +204,9 @@
[key] mod = {"Super", "Shift"} key = "F7" func = "tag_client" cmd = "6" [/key]
[key] mod = {"Super", "Shift"} key = "F8" func = "tag_client" cmd = "7" [/key]
[key] mod = {"Super"} key = "minus" func = "tag_del" [/key]
[key] mod = {"Super", "Shift"} key = "minus" func = "tag_new" [/key]
# tag function: cmd = nameofthetag
#[key] mod = {"Super"} key = "z" func = "tag" cmd = "2" [/key]
@ -191,6 +252,7 @@
[key] mod = {"Alt", "Shift"} key = "k" func = "client_tab_top" [/key]
[key] mod = {"Alt", "Shift"} key = "j" func = "client_tab_bottom" [/key]
[key] mod = {"Alt", "Shift"} key = "u" func = "client_untab" [/key]
[key] mod = {"Super"} key = "t" func = "client_tab_next_opened" [/key]
# Layout manipulation
[key] mod = {"Super"} key = "m" func = "layout_vmirror" [/key]
@ -198,8 +260,25 @@
[key] mod = {"Super"} key = "r" func = "layout_rotate_right" [/key]
[key] mod = {"Super", "Shift"} key = "r" func = "layout_rotate_left" [/key]
[key] mod = {"Control", "Super", "Alt"} key = "h" func = "layout_integrate_left" [/key]
[key] mod = {"Control", "Super", "Alt"} key = "j" func = "layout_integrate_bottom" [/key]
[key] mod = {"Control", "Super", "Alt"} key = "k" func = "layout_integrate_top" [/key]
[key] mod = {"Control", "Super", "Alt"} key = "l" func = "layout_integrate_right" [/key]
# Layout set historic travelling function (TESTING)
[key] mod = {"Super"} key = "o" func = "layout_prev_set" [/key]
[key] mod = {"Super"} key = "p" func = "layout_next_set" [/key]
[key] mod = {"Super", "Shift"} key = "o" func = "layout_next_set" [/key]
# Toggle client free/tile
[key] mod = {"Super"} key = "f" func = "client_toggle_free" [/key]
# Toggle client ignore_tag
[key] mod = {"Super", "Shift"} key = "f" func = "client_toggle_ignore_tag" [/key]
# Toggle infobar visibility
[key] mod = {"Super", "Shift"} key = "h" func = "infobar_toggle_hide" cmd = "default" [/key]
# Launcher
[key] mod = {"Super"} key = "p" func = "launcher" cmd = "exec" [/key]
[/keys]