-
Notifications
You must be signed in to change notification settings - Fork 590
/
client.lua
1781 lines (1597 loc) · 55.8 KB
/
client.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
---------------------------------------------------------------------------
--- Useful client manipulation functions.
--
-- @author Julien Danjou <julien@danjou.info>
-- @copyright 2008 Julien Danjou
-- @module client
---------------------------------------------------------------------------
-- Grab environment we need
local gdebug = require("gears.debug")
local spawn = nil --TODO v5 deprecate
local set_shape = require("awful.client.shape").update.all
local object = require("gears.object")
local grect = require("gears.geometry").rectangle
local gmath = require("gears.math")
local gtable = require("gears.table")
local amousec = require("awful.mouse.client")
local pcommon = require("awful.permissions._common")
local pairs = pairs
local type = type
local ipairs = ipairs
local table = table
local math = math
local setmetatable = setmetatable
local capi =
{
client = client,
mouse = mouse,
screen = screen,
awesome = awesome,
}
local function get_screen(s)
return s and capi.screen[s]
end
-- We use a metatable to prevent circular dependency loops.
local screen
do
screen = setmetatable({}, {
__index = function(_, k)
screen = require("awful.screen")
return screen[k]
end,
__newindex = error -- Just to be sure in case anything ever does this
})
end
local client = {object={}}
-- Private data
client.data = {}
client.data.marked = {}
client.data.persistent_properties_registered = {} -- keys are names of persistent properties, value always true
-- Functions
client.urgent = require("awful.client.urgent")
client.swap = {}
client.floating = {}
client.dockable = {}
client.property = {}
client.shape = require("awful.client.shape")
client.focus = require("awful.client.focus")
--- The client default placement on the screen.
--
-- The default config uses:
--
-- awful.placement.no_overlap+awful.placement.no_offscreen
--
-- @DOC_sequences_client_rules_placement_EXAMPLE@
--
-- @clientruleproperty placement
-- @see awful.placement
--- When applying the placement, honor the screen padding.
-- @clientruleproperty honor_padding
-- @tparam[opt=true] boolean honor_padding
-- @see awful.placement
--- When applying the placement, honor the screen work area.
--
-- The workarea is the part of the screen that excludes the bars and docks.
--
-- @clientruleproperty honor_workarea
-- @tparam[opt=true] boolean honor_workarea
-- @see awful.placement
--- The client default tag.
--
-- @DOC_sequences_client_rules_tags_EXAMPLE@
--
-- @clientruleproperty tag
-- @tparam tag tag
-- @see tag
-- @see new_tag
-- @see tags
-- @see switch_to_tags
--- The client default tags.
--
-- Avoid using the tag and tags properties at the same time, it will cause
-- issues.
--
-- @clientruleproperty tags
-- @tparam[opt={tag}] table tags
-- @see tag
-- @see new_tag
-- @see tags
-- @see switch_to_tags
--- Create a new tag for this client.
--
-- If the value is `true`, the new tag will be named after the client `class`.
-- If it is a string, it will be the tag name.
--
-- If a table is used, all of its properties will be passed to the tag
-- constructor:
--
-- @DOC_sequences_client_rules_new_tag_EXAMPLE@
--
-- @tparam[opt=false] table|string|boolean new_tag
-- @clientruleproperty new_tag
-- @see tag
-- @see tags
-- @see switch_to_tags
--- Unselect the current tags and select this client tags.
-- Note that this property was called `switchtotag` in previous Awesome versions.
--
-- @DOC_sequences_client_rules_switch_to_tags_EXAMPLE@
--
-- @clientruleproperty switch_to_tags
-- @tparam[opt=false] boolean switch_to_tags
-- @see tag.selected
--- Define if the client should grab focus by default.
--
-- The `request::activate` context for this call is `rules`.
--
-- @clientruleproperty focus
-- @tparam[opt=false] boolean focus
--- Should this client have a titlebar by default.
-- @clientruleproperty titlebars_enabled
-- @tparam[opt=false] boolean titlebars_enabled
-- @see awful.titlebar
--- A function to call when this client is ready.
--
-- It can be useful to set extra properties or perform actions.
--
-- @clientruleproperty callback
-- @see awful.spawn
--- Jump to the given client.
-- Takes care of focussing the screen, the right tag, etc.
--
-- @deprecated awful.client.jumpto
-- @see client.jump_to
-- @tparam client c the client to jump to
-- @tparam bool|function merge If true then merge tags (select the client's
-- first tag additionally) when the client is not visible.
-- If it is a function, it will be called with the client and its first
-- tag as arguments.
function client.jumpto(c, merge)
gdebug.deprecate("Use c:jump_to(merge) instead of awful.client.jumpto", {deprecated_in=4})
client.object.jump_to(c, merge)
end
--- Jump to the given client.
-- Takes care of focussing the screen, the right tag, etc.
--
-- @method jump_to
-- @tparam bool|function merge If true then merge tags (select the client's
-- first tag additionally) when the client is not visible.
-- If it is a function, it will be called with the client and its first
-- tag as arguments.
-- @request client activate client.jumpto granted When a client is activated
-- because `c:jump_to()` is called.
-- @see activate
-- @see active
function client.object.jump_to(self, merge)
local s = get_screen(screen.focused())
-- focus the screen
if s ~= get_screen(self.screen) then
screen.focus(self.screen)
end
self.minimized = false
-- Try to make client visible, this also covers e.g. sticky.
if not self:isvisible() then
local t = self.first_tag
if merge then
if type(merge) == "function" then
merge(self, t)
elseif t then
t.selected = true
end
elseif t then
t:view_only()
end
end
self:emit_signal("request::activate", "client.jumpto", {raise=true})
end
--- Get visible clients from a screen.
--
-- @deprecated awful.client.visible
-- @see screen.clients
-- @tparam[opt] integer|screen s The screen, or nil for all screens.
-- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom)
-- @treturn table A table with all visible clients.
function client.visible(s, stacked)
local cls = capi.client.get(s, stacked)
local vcls = {}
for _, c in pairs(cls) do
if c:isvisible() then
table.insert(vcls, c)
end
end
return vcls
end
--- Get visible and tiled clients
--
-- @deprecated awful.client.tiled
-- @see screen.tiled_clients
-- @tparam integer|screen s The screen, or nil for all screens.
-- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom)
-- @treturn table A table with all visible and tiled clients.
function client.tiled(s, stacked)
local clients = client.visible(s, stacked)
local tclients = {}
-- Remove floating clients
for _, c in pairs(clients) do
if not client.object.get_floating(c)
and not c.fullscreen
and not c.maximized
and not c.maximized_vertical
and not c.maximized_horizontal then
table.insert(tclients, c)
end
end
return tclients
end
--- Get a client by its relative index to another client.
-- If no client is passed, the focused client will be used.
--
-- @staticfct awful.client.next
-- @tparam int i The index. Use 1 to get the next, -1 to get the previous.
-- @tparam[opt] client sel The client.
-- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom)
-- @treturn[opt] client|nil A client, or nil if no client is available.
--
-- @usage -- focus the next window in the index
-- awful.client.next(1)
-- -- focus the previous
-- awful.client.next(-1)
function client.next(i, sel, stacked)
-- Get currently focused client
sel = sel or capi.client.focus
if sel then
-- Get all visible clients
local cls = client.visible(sel.screen, stacked)
local fcls = {}
-- Remove all non-normal clients
for _, c in ipairs(cls) do
if client.focus.filter(c) or c == sel then
table.insert(fcls, c)
end
end
cls = fcls
-- Loop upon each client
for idx, c in ipairs(cls) do
if c == sel then
-- Cycle
return cls[gmath.cycle(#cls, idx + i)]
end
end
end
end
--- Swap a client with another client in the given direction.
--
-- @staticfct awful.client.swap.bydirection
-- @tparam string dir The direction, can be either "up", "down", "left" or "right".
-- @tparam[opt=focused] client c The client.
-- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom)
-- @see swap
-- @see swapped
-- @see awful.client.swap.global_bydirection
-- @see awful.client.swap.byidx
-- @see awful.client.cycle
function client.swap.bydirection(dir, c, stacked)
local sel = c or capi.client.focus
if sel then
local cltbl = client.visible(sel.screen, stacked)
local geomtbl = {}
for i,cl in ipairs(cltbl) do
geomtbl[i] = cl:geometry()
end
local target = grect.get_in_direction(dir, geomtbl, sel:geometry())
-- If we found a client to swap with, then go for it
if target then
cltbl[target]:swap(sel)
end
end
end
--- Swap a client with another client in the given direction.
--
-- Swaps across screens.
-- @staticfct awful.client.swap.global_bydirection
-- @tparam string dir The direction, can be either "up", "down", "left" or "right".
-- @tparam[opt] client sel The client.
-- @request client activate client.swap.global_bydirection granted When a client
-- could be activated because `awful.client.swap.global_bydirection` was called.
-- @see swap
-- @see swapped
-- @see awful.client.swap.bydirection
-- @see awful.client.swap.byidx
-- @see awful.client.cycle
function client.swap.global_bydirection(dir, sel)
sel = sel or capi.client.focus
local scr = get_screen(sel and sel.screen or screen.focused())
if sel then
-- move focus
client.focus.global_bydirection(dir, sel)
local c = capi.client.focus
-- swapping inside a screen
if get_screen(sel.screen) == get_screen(c.screen) and sel ~= c then
c:swap(sel)
-- swapping to an empty screen
elseif sel == c then
sel:move_to_screen(screen.focused())
-- swapping to a nonempty screen
elseif get_screen(sel.screen) ~= get_screen(c.screen) and sel ~= c then
sel:move_to_screen(c.screen)
c:move_to_screen(scr)
end
screen.focus(sel.screen)
sel:emit_signal("request::activate", "client.swap.global_bydirection",
{raise=false})
end
end
--- Swap a client by its relative index.
--
-- @staticfct awful.client.swap.byidx
-- @tparam integer i The index.
-- @tparam[opt] client c The client, otherwise focused one is used.
-- @see swap
-- @see swapped
-- @see awful.client.swap.bydirection
-- @see awful.client.swap.global_bydirection
-- @see awful.client.cycle
function client.swap.byidx(i, c)
local sel = c or capi.client.focus
local target = client.next(i, sel)
if target then
target:swap(sel)
end
end
--- Cycle through the clients to change the focus.
--
-- This will swap the client from one position to the next
-- in the layout.
--
-- @staticfct awful.client.cycle
-- @tparam boolean clockwise True to cycle clients clockwise.
-- @tparam[opt] screen s The screen where to cycle clients.
-- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom)
-- @see swap
-- @see swapped
-- @see awful.client.swap.bydirection
-- @see awful.client.swap.global_bydirection
-- @see awful.client.swap.byidx
function client.cycle(clockwise, s, stacked)
s = s or screen.focused()
local cls = client.visible(s, stacked)
-- We can't rotate without at least 2 clients, buddy.
if #cls >= 2 then
local c = table.remove(cls, 1)
if clockwise then
for i = #cls, 1, -1 do
c:swap(cls[i])
end
else
for _, rc in pairs(cls) do
c:swap(rc)
end
end
end
end
--- Append a keybinding.
--
-- @method append_keybinding
-- @tparam awful.key key The key.
-- @see remove_keybinding
-- @see append_mousebinding
-- @see remove_mousebinding
--- Remove a keybinding.
--
-- @method remove_keybinding
-- @tparam awful.key key The key.
--- Append a mousebinding.
--
-- @method append_mousebinding
-- @tparam awful.button button The button.
--- Remove a mousebinding.
--
-- @method remove_mousebinding
-- @tparam awful.button button The button.
--- Get the master window.
--
-- @legacylayout awful.client.getmaster
-- @tparam[opt=awful.screen.focused()] screen s The screen.
-- @treturn client The master client.
function client.getmaster(s)
s = s or screen.focused()
return client.visible(s)[1]
end
--- Set the client as master: put it at the beginning of other windows.
--
-- @legacylayout awful.client.setmaster
-- @tparam client c The window to set as master.
function client.setmaster(c)
local cls = gtable.reverse(capi.client.get(c.screen))
for _, v in pairs(cls) do
c:swap(v)
end
end
--- Set the client as slave: put it at the end of other windows.
-- @legacylayout awful.client.setslave
-- @tparam client c The window to set as slave.
function client.setslave(c)
local cls = capi.client.get(c.screen)
for _, v in pairs(cls) do
c:swap(v)
end
end
--- Move/resize a client relative to current coordinates.
-- @deprecated awful.client.moveresize
-- @tparam integer x The relative x coordinate.
-- @tparam integer y The relative y coordinate.
-- @tparam integer w The relative width.
-- @tparam integer h The relative height.
-- @tparam[opt] client c The client, otherwise focused one is used.
-- @see client.relative_move
function client.moveresize(x, y, w, h, c)
gdebug.deprecate("Use c:relative_move(x, y, w, h) instead of awful.client.moveresize", {deprecated_in=4})
client.object.relative_move(c or capi.client.focus, x, y, w, h)
end
--- Move/resize a client relative to current coordinates.
-- @method relative_move
-- @see geometry
-- @tparam[opt=c.x] number x The relative x coordinate.
-- @tparam[opt=c.y] number y The relative y coordinate.
-- @tparam[opt=c.width] number w The relative width.
-- @tparam[opt=c.height] number h The relative height.
function client.object.relative_move(self, x, y, w, h)
local geometry = self:geometry()
geometry['x'] = geometry['x'] + x
geometry['y'] = geometry['y'] + y
geometry['width'] = geometry['width'] + w
geometry['height'] = geometry['height'] + h
self:geometry(geometry)
end
--- Move a client to a tag.
-- @deprecated awful.client.movetotag
-- @tparam tag target The tag to move the client to.
-- @tparam[opt] client c The client to move, otherwise the focused one is used.
-- @see client.move_to_tag
function client.movetotag(target, c)
gdebug.deprecate("Use c:move_to_tag(target) instead of awful.client.movetotag", {deprecated_in=4})
client.object.move_to_tag(c or capi.client.focus, target)
end
--- Move a client to a tag.
--
-- @method move_to_tag
-- @tparam tag target The tag to move the client to.
-- @request client activate client.movetotag granted When a client could be
-- activated because `c:move_to_tag()` was called.
-- @see tags
function client.object.move_to_tag(self, target)
local s = target.screen
if self and s then
if self == capi.client.focus then
self:emit_signal("request::activate", "client.movetotag", {raise=true})
end
-- Set client on the same screen as the tag.
self.screen = s
self:tags({ target })
end
end
--- Toggle a tag on a client.
--
-- @deprecated awful.client.toggletag
-- @tparam tag target The tag to toggle.
-- @tparam[opt] client c The client to toggle, otherwise the focused one is used.
-- @see client.toggle_tag
-- @see tags
function client.toggletag(target, c)
gdebug.deprecate("Use c:toggle_tag(target) instead of awful.client.toggletag", {deprecated_in=4})
client.object.toggle_tag(c or capi.client.focus, target)
end
--- Toggle a tag on a client.
--
-- @method toggle_tag
-- @tparam tag target The tag to move the client to.
-- @see tags
function client.object.toggle_tag(self, target)
-- Check that tag and client screen are identical
if self and get_screen(self.screen) == get_screen(target.screen) then
local tags = self:tags()
local index = nil;
for i, v in ipairs(tags) do
if v == target then
index = i
break
end
end
if index then
-- If it's the only tag for the window, stop.
if #tags == 1 then return end
tags[index] = nil
else
tags[#tags + 1] = target
end
self:tags(tags)
end
end
--- Move a client to a screen. Default is next screen, cycling.
-- @deprecated awful.client.movetoscreen
-- @tparam client c The client to move.
-- @tparam screen s The screen, default to current + 1.
-- @see screen
-- @see client.move_to_screen
function client.movetoscreen(c, s)
gdebug.deprecate("Use c:move_to_screen(s) instead of awful.client.movetoscreen", {deprecated_in=4})
client.object.move_to_screen(c or capi.client.focus, s)
end
--- Move a client to a screen. Default is next screen, cycling.
-- @method move_to_screen
-- @tparam[opt=c.screen.index+1] screen s The screen, default to current + 1.
-- @see screen
-- @see request::activate
-- @request client activate client.movetoscreen granted When a client could be
-- activated because `c:move_to_screen()` was called.
function client.object.move_to_screen(self, s)
if self then
local sc = capi.screen.count()
if not s then
s = self.screen.index + 1
end
if type(s) == "number" then
if s > sc then s = 1 elseif s < 1 then s = sc end
end
s = get_screen(s)
if get_screen(self.screen) ~= s then
local sel_is_focused = self.active
self.screen = s
screen.focus(s)
if sel_is_focused then
self:emit_signal("request::activate", "client.movetoscreen",
{raise=true})
end
end
end
end
--- Tag a client with the set of current tags.
-- @method to_selected_tags
-- @see screen.selected_tags
function client.object.to_selected_tags(self)
local tags = {}
for _, t in ipairs(self:tags()) do
if get_screen(t.screen) == get_screen(self.screen) then
table.insert(tags, t)
end
end
if self.screen then
if #tags == 0 then
tags = self.screen.selected_tags
end
if #tags == 0 then
tags = self.screen.tags
end
end
if #tags ~= 0 then
self:tags(tags)
end
end
--- If a client is marked or not.
--
-- @property marked
-- @tparam boolean marked
-- @emits marked (for legacy reasons, use `property::marked`)
-- @emits unmarker (for legacy reasons, use `property::marked`)
-- @emits property::marked
function client.object.set_marked(self, value)
local is_marked = self.marked
if value == false and is_marked then
for k, v in pairs(client.data.marked) do
if self == v then
table.remove(client.data.marked, k)
end
end
self:emit_signal("unmarked")
elseif not is_marked and value then
self:emit_signal("marked")
table.insert(client.data.marked, self)
end
client.property.set(self, "marked", value)
end
function client.object.get_marked(self)
return client.property.get(self, "marked")
end
--- Mark a client, and then call 'marked' hook.
-- @deprecated awful.client.mark
-- @tparam client c The client to mark, the focused one if not specified.
function client.mark(c)
gdebug.deprecate("Use c.marked = true instead of awful.client.mark", {deprecated_in=4})
client.object.set_marked(c or capi.client.focus, true)
end
--- Unmark a client and then call 'unmarked' hook.
-- @deprecated awful.client.unmark
-- @tparam client c The client to unmark, or the focused one if not specified.
function client.unmark(c)
gdebug.deprecate("Use c.marked = false instead of awful.client.unmark", {deprecated_in=4})
client.object.set_marked(c or capi.client.focus, false)
end
--- Check if a client is marked.
-- @deprecated awful.client.ismarked
-- @tparam client c The client to check, or the focused one otherwise.
function client.ismarked(c)
gdebug.deprecate("Use c.marked instead of awful.client.ismarked", {deprecated_in=4})
return client.object.get_marked(c or capi.client.focus)
end
--- Toggle a client as marked.
-- @deprecated awful.client.togglemarked
-- @tparam client c The client to toggle mark.
function client.togglemarked(c)
gdebug.deprecate("Use c.marked = not c.marked instead of awful.client.togglemarked", {deprecated_in=4})
c = c or capi.client.focus
if c then
c.marked = not c.marked
end
end
--- Return the marked clients and empty the marked table.
-- @deprecated awful.client.getmarked
-- @treturn table A table with all marked clients.
function client.getmarked()
local copy = gtable.clone(client.data.marked, false)
for _, v in pairs(copy) do
client.property.set(v, "marked", false)
v:emit_signal("unmarked")
end
client.data.marked = {}
return copy
end
--- Set a client floating state, overriding auto-detection.
-- Floating client are not handled by tiling layouts.
-- @deprecated awful.client.floating.set
-- @tparam client c A client.
-- @tparam boolean s True or false.
function client.floating.set(c, s)
gdebug.deprecate("Use c.floating = true instead of awful.client.floating.set", {deprecated_in=4})
client.object.set_floating(c, s)
end
-- Set a client floating state, overriding auto-detection.
-- Floating client are not handled by tiling layouts.
-- @tparam client c A client.
-- @tparam boolan s True or false.
function client.object.set_floating(c, s)
c = c or capi.client.focus
if c and client.property.get(c, "floating") ~= s then
client.property.set(c, "floating", s)
local scr = c.screen
if s == true then
c:geometry(client.property.get(c, "floating_geometry"))
end
c.screen = scr
if s then
c:emit_signal("request::border", "floating", {})
else
c:emit_signal("request::border", (c.active and "" or "in").."active", {})
end
end
end
local function store_floating_geometry(c)
if client.object.get_floating(c) then
client.property.set(c, "floating_geometry", c:geometry())
end
end
-- Store the initial client geometry.
capi.client.connect_signal("new", function(cl)
local function store_init_geometry(c)
client.property.set(c, "floating_geometry", c:geometry())
c:disconnect_signal("property::border_width", store_init_geometry)
end
cl:connect_signal("property::border_width", store_init_geometry)
end)
capi.client.connect_signal("property::geometry", store_floating_geometry)
--- Return if a client has a fixed size or not.
-- This function is deprecated, use `c.is_fixed`
-- @tparam client c The client.
-- @deprecated awful.client.isfixed
-- @see is_fixed
-- @see size_hints_honor
function client.isfixed(c)
gdebug.deprecate("Use c.is_fixed instead of awful.client.isfixed", {deprecated_in=4})
c = c or capi.client.focus
return client.object.is_fixed(c)
end
--- Return if a client has a fixed size or not.
--
-- This property is read only.
-- @property is_fixed
-- @tparam[opt=false] boolean is_fixed The fixed size state
-- @propemits false false
-- @see size_hints
-- @see size_hints_honor
function client.object.is_fixed(c)
if not c then return end
local h = c.size_hints
if h.min_width and h.max_width
and h.max_height and h.min_height
and h.min_width > 0 and h.max_width > 0
and h.max_height > 0 and h.min_height > 0
and h.min_width == h.max_width
and h.min_height == h.max_height then
return true
end
return false
end
--- Is the client immobilized horizontally?
--
-- Does the client have a fixed horizontal position and width, i.e. is it
-- fullscreen, maximized, or horizontally maximized?
--
-- This property is read only.
-- @property immobilized_horizontal
-- @tparam[opt=false] boolean immobilized_horizontal The immobilized state
-- @see maximized
-- @see maximized_horizontal
-- @see fullscreen
function client.object.is_immobilized_horizontal(c)
return c.fullscreen or c.maximized or c.maximized_horizontal
end
--- Is the client immobilized vertically?
--
-- Does the client have a fixed vertical position and width, i.e. is it
-- fullscreen, maximized, or vertically maximized?
--
-- This property is read only.
-- @property immobilized_vertical
-- @tparam[opt=false] boolean immobilized_vertical The immobilized state
-- @see maximized
-- @see maximized_vertical
-- @see fullscreen
function client.object.is_immobilized_vertical(c)
return c.fullscreen or c.maximized or c.maximized_vertical
end
--- Get a client floating state.
-- @tparam client c A client.
-- @see floating
-- @deprecated awful.client.floating.get
-- @treturn boolean True or false. Note that some windows might be floating even if you
-- did not set them manually. For example, windows with a type different than
-- normal.
function client.floating.get(c)
gdebug.deprecate("Use c.floating instead of awful.client.floating.get", {deprecated_in=4})
return client.object.get_floating(c)
end
--- The client floating state.
--
-- If the client is part of the tiled layout or free floating.
--
-- Note that some windows might be floating even if you
-- did not set them manually. For example, windows with a type different than
-- normal.
--
-- @property floating
-- @tparam boolean floating The floating state.
-- @request client border floating granted When a border update is required
-- because the client focus status changed.
-- @request client border active granted When a client becomes active and is not
-- floating.
-- @request client border inactive granted When a client stop being active and
-- is not floating.
-- @propemits false false
function client.object.get_floating(c)
c = c or capi.client.focus
if c then
local value = client.property.get(c, "floating")
if value ~= nil then
return value
end
return client.property.get(c, "_implicitly_floating") or false
end
end
-- When a client is not explicitly assigned a floating state, it might
-- implicitly end up being floating. The following makes sure that
-- property::floating is still emitted if this implicit floating state changes.
local function update_implicitly_floating(c)
local explicit = client.property.get(c, "floating")
if explicit ~= nil then
return
end
local cur = client.property.get(c, "_implicitly_floating")
local new = c.type ~= "normal"
or c.fullscreen
or c.maximized_vertical
or c.maximized_horizontal
or c.maximized
or client.object.is_fixed(c)
if cur ~= new then
client.property.set(c, "_implicitly_floating", new)
c:emit_signal("property::floating")
-- Don't send the border signals as they would be sent twice (with this
-- one having the wrong context). There is some `property::` signal
-- sent before `request::manage`.
if client.property.get(c, "_border_init") then
if cur then
c:emit_signal("request::border", "floating", {})
else
c:emit_signal("request::border", (c.active and "" or "in").."active", {})
end
end
end
end
capi.client.connect_signal("property::type", update_implicitly_floating)
capi.client.connect_signal("property::fullscreen", update_implicitly_floating)
capi.client.connect_signal("property::maximized_vertical", update_implicitly_floating)
capi.client.connect_signal("property::maximized_horizontal", update_implicitly_floating)
capi.client.connect_signal("property::maximized", update_implicitly_floating)
capi.client.connect_signal("property::size_hints", update_implicitly_floating)
capi.client.connect_signal("request::manage", update_implicitly_floating)
--- Toggle the floating state of a client between 'auto' and 'true'.
-- Use `c.floating = not c.floating`
-- @deprecated awful.client.floating.toggle
-- @tparam client c A client.
-- @see floating
function client.floating.toggle(c)
c = c or capi.client.focus
-- If it has been set to floating
client.object.set_floating(c, not client.object.get_floating(c))
end
-- Remove the floating information on a client.
-- @tparam client c The client.
function client.floating.delete(c)
client.object.set_floating(c, nil)
end
--- The x coordinates.
--
-- @property x
-- @tparam integer x
-- @emits property::geometry
-- @emitstparam property::geometry table geo The
-- geometry (with `x`, `y`, `width`, `height`).
-- @emits property::x
-- @emits property::position
--- The y coordinates.
--
-- @property y
-- @tparam integer y
-- @emits property::geometry
-- @emitstparam property::geometry table geo The
-- geometry (with `x`, `y`, `width`, `height`).
-- @emits property::y
-- @emits property::position
--- The width of the client.
--
-- @property width
-- @tparam integer width
-- @emits property::geometry
-- @emitstparam property::geometry table geo The
-- geometry (with `x`, `y`, `width`, `height`).
-- @emits property::width
-- @emits property::size
--- The height of the client.
--
-- @property height
-- @tparam integer height
-- @emits property::geometry
-- @emitstparam property::geometry table geo The
-- geometry (with `x`, `y`, `width`, `height`).
-- @emits property::height
-- @emits property::size
-- Add the geometry helpers to match the wibox API
for _, v in ipairs {"x", "y", "width", "height"} do
client.object["get_"..v] = function(c)
return c:geometry()[v]
end
client.object["set_"..v] = function(c, value)
return c:geometry({[v] = value})
end
end
--- Restore (=unminimize) a random client.
-- @staticfct awful.client.restore
-- @tparam screen s The screen to use.
-- @treturn client The restored client if some client was restored, otherwise nil.
function client.restore(s)
s = s or screen.focused()
local cls = capi.client.get(s)
local tags = s.selected_tags
for _, c in pairs(cls) do
local ctags = c:tags()
if c.minimized then
for _, t in ipairs(tags) do
if gtable.hasitem(ctags, t) then
c.minimized = false
return c
end
end
end
end
return nil
end
--- Normalize a set of numbers to 1.
-- @tparam table set the set of numbers to normalize.
-- @tparam number num the number of numbers to normalize.
local function normalize(set, num)
num = num or #set
local total = 0