Browse Source

init: Add a command line option to start AwesomeWM without screens.

This commit add an optional `--screen off` command to initialize Lua
without first adding the screens. This is inconvinient for most users
since it restrict the APIs that are usable out of the box.

However, this allows AwesomeWM to work independently from the hardware.
This means that when a screen is unplugged, it is the Lua code that will
remove the screen instead of CAPI pulling the carpet from under. It also
allows to ignore some screen areas before the screen is ever created.
Combined, it makes it possible to work with screens even when they are
physically disconnected. Finally, it will allow for an awful.rules like
API to control how screens are created.

All in all, some people need this for their setup and some people might
want to do it anyway for fine grained and/or dynamaic multi-screen
setups.

This commit also adds 4 new signals to `capi` to be able to
execute code at specific points during the initialization. The commit
improves naughty error notifications to work even if problems occurs
before the screens are added.

Note that AwesomeWM will exit if no screens are created. While it would
be easy to just call `refresh_screen();` after unsetting the magic
variable, doing so would have corner cases. Better be harsher and
prevent the user from shooting themselves in the foot from not reading
the f****** manual. Code introduced in future commits will take care
of automatically calling fake_screen in the event nothing is created.

Fixes #1382
Emmanuel Lepage Vallee 1 year ago
parent
commit
433898599d
8 changed files with 500 additions and 28 deletions
  1. 37
    9
      awesome.c
  2. 5
    0
      globalconf.h
  3. 44
    1
      lib/naughty/init.lua
  4. 11
    8
      luaa.c
  5. 29
    0
      objects/client.c
  6. 2
    0
      objects/client.h
  7. 370
    10
      objects/screen.c
  8. 2
    0
      objects/screen.h

+ 37
- 9
awesome.c View File

@@ -559,13 +559,14 @@ exit_help(int exit_code)
559 559
     FILE *outfile = (exit_code == EXIT_SUCCESS) ? stdout : stderr;
560 560
     fprintf(outfile,
561 561
 "Usage: awesome [OPTION]\n\
562
-  -h, --help             show help\n\
563
-  -v, --version          show version\n\
564
-  -c, --config FILE      configuration file to use\n\
565
-      --search DIR       add a directory to the library search path\n\
566
-  -k, --check            check configuration file syntax\n\
567
-  -a, --no-argb          disable client transparency support\n\
568
-  -r, --replace          replace an existing window manager\n");
562
+  -h, --help           show help\n\
563
+  -v, --version        show version\n\
564
+  -c, --config FILE    configuration file to use\n\
565
+      --search DIR     add a directory to the library search path\n\
566
+  -k, --check          check configuration file syntax\n\
567
+  -a, --no-argb        disable client transparency support\n\
568
+  -m, --screen on|off  enable or disable automatic screen creation (default: on)\n\
569
+  -r, --replace        replace an existing window manager\n");
569 570
     exit(exit_code);
570 571
 }
571 572
 
@@ -594,6 +595,7 @@ main(int argc, char **argv)
594 595
         { "search",  1, NULL, 's' },
595 596
         { "no-argb", 0, NULL, 'a' },
596 597
         { "replace", 0, NULL, 'r' },
598
+        { "screen" , 1, NULL, 'm' },
597 599
         { "reap",    1, NULL, '\1' },
598 600
         { NULL,      0, NULL, 0 }
599 601
     };
@@ -634,6 +636,14 @@ main(int argc, char **argv)
634 636
             if (confpath != NULL)
635 637
                 fatal("--config may only be specified once");
636 638
             confpath = a_strdup(optarg);
639
+            break;
640
+          case 'm':
641
+            /* Validation */
642
+            if ((!optarg) || !(A_STREQ(optarg, "off") || A_STREQ(optarg, "on")))
643
+                fatal("The possible values of -m/--screen are \"on\" or \"off\"");
644
+
645
+            globalconf.no_auto_screen = A_STREQ(optarg, "off");
646
+
637 647
             break;
638 648
           case 's':
639 649
             string_array_append(&searchpath, a_strdup(optarg));
@@ -901,20 +911,38 @@ main(int argc, char **argv)
901 911
 
902 912
     ewmh_init_lua();
903 913
 
914
+    /* Parse and run configuration file before adding the screens */
915
+    if (globalconf.no_auto_screen && !luaA_parserc(&xdg, confpath))
916
+        fatal("couldn't find any rc file");
917
+
904 918
     /* init screens information */
905 919
     screen_scan();
906 920
 
907
-    /* Parse and run configuration file */
908
-    if (!luaA_parserc(&xdg, confpath))
921
+    /* Parse and run configuration file after adding the screens */
922
+    if (((!globalconf.no_auto_screen) && !luaA_parserc(&xdg, confpath)))
909 923
         fatal("couldn't find any rc file");
910 924
 
911 925
     p_delete(&confpath);
912 926
 
913 927
     xdgWipeHandle(&xdg);
914 928
 
929
+    /* Both screen scanning mode have this signal, it cannot be in screen_scan
930
+       since the automatic screen generation don't have executed rc.lua yet. */
931
+    screen_emit_scanned();
932
+
933
+    /* Exit if the user doesn't read the instructions properly */
934
+    if (globalconf.no_auto_screen && !globalconf.screens.len)
935
+        fatal("When -m/--screen is set to \"off\", you **must** create a "
936
+              "screen object before or inside the screen \"scanned\" "
937
+              " signal. Using AwesomeWM with no screen is **not supported**.");
938
+
939
+    client_emit_scanning();
940
+
915 941
     /* scan existing windows */
916 942
     scan(tree_c);
917 943
 
944
+    client_emit_scanned();
945
+
918 946
     luaA_emit_startup();
919 947
 
920 948
     /* Setup the main context */

+ 5
- 0
globalconf.h View File

@@ -55,6 +55,7 @@
55 55
     }
56 56
 
57 57
 typedef struct drawable_t drawable_t;
58
+typedef struct a_screen_area screen_area_t;
58 59
 typedef struct drawin_t drawin_t;
59 60
 typedef struct a_screen screen_t;
60 61
 typedef struct button_t button_t;
@@ -111,6 +112,10 @@ typedef struct
111 112
     bool have_randr_15;
112 113
     /** Do we have a RandR screen update pending? */
113 114
     bool screen_refresh_pending;
115
+    /** Should screens be created before rc.lua is loaded? */
116
+    bool no_auto_screen;
117
+    /** Should the screen be created automatically? */
118
+    bool ignore_screens;
114 119
     /** Check for XTest extension */
115 120
     bool have_xtest;
116 121
     /** Check for SHAPE extension */

+ 44
- 1
lib/naughty/init.lua View File

@@ -5,6 +5,7 @@
5 5
 ---------------------------------------------------------------------------
6 6
 
7 7
 local naughty = require("naughty.core")
8
+local gdebug = require("gears.debug")
8 9
 local capi = {awesome = awesome}
9 10
 if dbus then
10 11
     naughty.dbus = require("naughty.dbus")
@@ -18,11 +19,48 @@ naughty.container = require("naughty.container")
18 19
 naughty.action = require("naughty.action")
19 20
 naughty.notification = require("naughty.notification")
20 21
 
22
+-- Attempt to handle early errors when using the manual screen mode.
23
+--
24
+-- Creating a notification popup before the screens are added won't work. To
25
+-- work around this, the code below initializes some screens. One potential
26
+-- problem is that it could emit enough signal to cause even more errors and
27
+-- lose the original error.
28
+--
29
+-- For example, the following error can be displayed using this fallback:
30
+--
31
+--    screen.connect_signal("scanned", function() foobar() end)
32
+--
33
+local function screen_fallback()
34
+    if screen.count() == 0 then
35
+        gdebug.print_warning("An error occurred before a scrren was added")
36
+
37
+        -- Private API to scan for screens now.
38
+        if #screen._viewports() == 0 then
39
+            screen._scan_quiet()
40
+        end
41
+
42
+        local viewports = screen._viewports()
43
+
44
+        if #viewports > 0 then
45
+            for _, viewport in ipairs(viewports) do
46
+                local geo = viewport.geometry
47
+                screen.fake_add(geo.x, geo.y, geo.width, geo.height)
48
+            end
49
+        else
50
+            screen.fake_add(0, 0, 640, 480)
51
+        end
52
+    end
53
+end
54
+
21 55
 -- Handle runtime errors during startup
22 56
 if capi.awesome.startup_errors then
57
+
23 58
     -- Wait until `rc.lua` is executed before creating the notifications.
24 59
     -- Otherwise nothing is handling them (yet).
25
-    awesome.connect_signal("startup", function()
60
+    client.connect_signal("scanning", function()
61
+        -- A lot of things have to go wrong for this to happen, but it can.
62
+        screen_fallback()
63
+
26 64
         naughty.emit_signal(
27 65
             "request::display_error", capi.awesome.startup_errors, true
28 66
         )
@@ -32,15 +70,20 @@ end
32 70
 -- Handle runtime errors after startup
33 71
 do
34 72
     local in_error = false
73
+
35 74
     capi.awesome.connect_signal("debug::error", function (err)
36 75
         -- Make sure we don't go into an endless error loop
37 76
         if in_error then return end
77
+
38 78
         in_error = true
39 79
 
80
+        screen_fallback()
81
+
40 82
         naughty.emit_signal("request::display_error", tostring(err), false)
41 83
 
42 84
         in_error = false
43 85
     end)
86
+
44 87
 end
45 88
 
46 89
 return naughty

+ 11
- 8
luaa.c View File

@@ -19,14 +19,17 @@
19 19
  *
20 20
  */
21 21
 
22
-/** awesome core API
22
+/** AwesomeWM lifecycle API.
23 23
  *
24
- * Additionally to the classes described here, one can also use X properties as
25
- * described in @{xproperties}.
24
+ * This module contains the functions and signal to manage the lifecycle of the
25
+ * AwesomeWM process. It allows to execute code at specific point from the early
26
+ * initialization all the way to the last events before exiting or restarting.
27
+ *
28
+ * Additionally it handles signals for spawn and keyboard related events.
26 29
  *
27 30
  * @author Julien Danjou <julien@danjou.info>
28 31
  * @copyright 2008-2009 Julien Danjou
29
- * @module awesome
32
+ * @coreclassmod awesome
30 33
  */
31 34
 
32 35
 /** Register a new xproperty.
@@ -150,13 +153,13 @@ extern const struct luaL_Reg awesome_mouse_meta[];
150 153
  * @signal refresh
151 154
  */
152 155
 
153
-/** Awesome is about to enter the event loop.
156
+/** AwesomeWM is about to enter the event loop.
154 157
  *
155 158
  * This means all initialization has been done.
156 159
  * @signal startup
157 160
  */
158 161
 
159
-/** Awesome is exiting / about to restart.
162
+/** AwesomeWM is exiting / about to restart.
160 163
  *
161 164
  * This signal is emitted in the `atexit` handler as well when awesome
162 165
  * restarts.
@@ -167,8 +170,8 @@ extern const struct luaL_Reg awesome_mouse_meta[];
167 170
 
168 171
 /** The output status of a screen has changed.
169 172
  *
170
- * @param output String containing which output has changed.
171
- * @param connection_state String containing the connection status of
173
+ * @tparam string output String containing which output has changed.
174
+ * @tparam string connection_state String containing the connection status of
172 175
  * the output: It will be either "Connected", "Disconnected" or
173 176
  * "Unknown".
174 177
  * @signal screen::change

+ 29
- 0
objects/client.c View File

@@ -132,6 +132,21 @@
132 132
  * @table awful.object
133 133
  */
134 134
 
135
+/** AwesomeWM is about to scan for existing clients.
136
+ *
137
+ * Connect to this signal when code needs to be executed after screens are
138
+ * initialized, but before clients are added.
139
+ *
140
+ * @signal scanning
141
+ */
142
+
143
+/** AwesomeWM is done scanning for clients.
144
+ *
145
+ * This is emitted before the `startup` signal and after the `scanning` signal.
146
+ *
147
+ * @signal scanned
148
+ */
149
+
135 150
 /** When a client gains focus.
136 151
  * @signal focus
137 152
  */
@@ -1038,6 +1053,20 @@ DO_CLIENT_SET_STRING_PROPERTY(role)
1038 1053
 DO_CLIENT_SET_STRING_PROPERTY(machine)
1039 1054
 #undef DO_CLIENT_SET_STRING_PROPERTY
1040 1055
 
1056
+void
1057
+client_emit_scanned(void)
1058
+{
1059
+    lua_State *L = globalconf_get_lua_State();
1060
+    luaA_class_emit_signal(L, &client_class, "scanned", 0);
1061
+}
1062
+
1063
+void
1064
+client_emit_scanning(void)
1065
+{
1066
+    lua_State *L = globalconf_get_lua_State();
1067
+    luaA_class_emit_signal(L, &client_class, "scanning", 0);
1068
+}
1069
+
1041 1070
 void
1042 1071
 client_set_motif_wm_hints(lua_State *L, int cidx, motif_wm_hints_t hints)
1043 1072
 {

+ 2
- 0
objects/client.h View File

@@ -244,6 +244,8 @@ void client_refresh_partial(client_t *, int16_t, int16_t, uint16_t, uint16_t);
244 244
 void client_class_setup(lua_State *);
245 245
 void client_send_configure(client_t *);
246 246
 void client_find_transient_for(client_t *);
247
+void client_emit_scanned(void);
248
+void client_emit_scanning(void);
247 249
 drawable_t *client_get_drawable(client_t *, int, int);
248 250
 drawable_t *client_get_drawable_offset(client_t *, int *, int *);
249 251
 

+ 370
- 10
objects/screen.c View File

@@ -62,6 +62,37 @@
62 62
  */
63 63
 #define FAKE_SCREEN_XID ((uint32_t) 0xffffffff)
64 64
 
65
+/** AwesomeWM is about to scan for existing screens.
66
+ *
67
+ * Connect to this signal when code needs to be executed after the Lua context
68
+ * is initialized and modules are loaded, but before screens are added.
69
+ *
70
+ * To manage screens manually, set `screen.automatic_factory = false` and
71
+ * connect to the `property::viewports` signal. It is then possible to use
72
+ * `screen.fake_add` to create virtual screens. Be careful when using this,
73
+ * when done incorrectly, no screens will be created. Using Awesome with zero
74
+ * screens is **not** supported.
75
+ *
76
+ * @signal scanning
77
+ * @see property::viewports
78
+ * @see screen.fake_add
79
+ */
80
+
81
+/** AwesomeWM is done scanning for screens.
82
+ *
83
+ * Connect to this signal to execute code after the screens have been created,
84
+ * but before the clients are added. This signal can also be used to split
85
+ * physical screens into multiple virtual screens before the clients (and their
86
+ * rules) are executed.
87
+ *
88
+ * Note that if no screens exist at this point, the fallback code will be
89
+ * triggered and the default (detected) screens will be added.
90
+ *
91
+ * @signal scanned
92
+ * @see screen.fake_resize
93
+ * @see screen.fake_add
94
+ */
95
+
65 96
 /** Screen is a table where indexes are screen numbers. You can use `screen[1]`
66 97
  * to get access to the first screen, etc. Alternatively, if RANDR information
67 98
  * is available, you can use output names for finding screen objects.
@@ -94,12 +125,33 @@
94 125
  * @signal swapped
95 126
  */
96 127
 
128
+/** This signal is emitted when the list of physical screen viewport changes.
129
+ *
130
+ * Each viewport in the list corresponds to a **physical** screen rectangle, which
131
+ * is **not** the `viewports` property of the `screen` objects.
132
+ *
133
+ * @signal property::viewports
134
+ * @tparam table viewports
135
+ * @see automatic_factory
136
+ */
137
+
97 138
  /**
98 139
   * The primary screen.
99 140
   *
100 141
   * @tfield screen primary
101 142
   */
102 143
 
144
+/**
145
+ * If `screen` objects are created automatically when new viewports are detected.
146
+ *
147
+ * Be very, very careful when setting this to false. You might end up with
148
+ * no screens. This is **not** supported. Always connect to the `scanned`
149
+ * signal to make sure to create a fallback screen if none were created.
150
+ *
151
+ * @tfield[opt=true] boolean screen.automatic_factory
152
+ * @see property::viewports
153
+ */
154
+
103 155
 /**
104 156
  * The screen coordinates.
105 157
  *
@@ -297,6 +349,192 @@ screen_deduplicate(lua_State *L, screen_array_t *screens)
297 349
     }
298 350
 }
299 351
 
352
+/** Keep track of the screen viewport(s) independently from the screen objects.
353
+ *
354
+ * A viewport is a collection of `outputs` objects and their associated
355
+ * metadata. This structure is copied into Lua and then further extended from
356
+ * there. The `id` field allows to differentiate between viewports that share
357
+ * the same position and dimensions without having to rely on userdata pointer
358
+ * comparison.
359
+ *
360
+ * Screen objects are widely used by the public API and imply a very "visible"
361
+ * concept. A viewport is a subset of what the concerns the "screen" class
362
+ * previously handled. It is meant to be used by some low level Lua logic to
363
+ * create screens from Lua rather than from C. This is required to increase the
364
+ * flexibility of multi-screen setup or when screens are connected and
365
+ * disconnected often.
366
+ *
367
+ * Design rationals:
368
+ *
369
+ * * The structure is not directly shared with Lua to avoid having to use the
370
+ *   slow "miss_handler" and unsafe "valid" systems used by other CAPI objects.
371
+ * * The `viewport_t` implements a linked-list because its main purpose is to
372
+ *   offers a deduplication algorithm. Random access is never required.
373
+ * * Everything that can be done in Lua is done in Lua.
374
+ * * Since the legacy and "new" way to initialize screens share a lot of steps,
375
+ *   the C code is bent to share as much code as possible. This will reduce the
376
+ *   "dead code" and improve code coverage by the tests.
377
+ *
378
+ */
379
+typedef struct viewport_t
380
+{
381
+    bool marked;
382
+    int x;
383
+    int y;
384
+    int width;
385
+    int height;
386
+    struct viewport_t *next;
387
+    screen_t *screen;
388
+} viewport_t;
389
+
390
+static viewport_t *first_screen_viewport = NULL;
391
+static viewport_t *last_screen_viewport = NULL;
392
+
393
+static int
394
+luaA_viewports(lua_State *L)
395
+{
396
+    /* All viewports */
397
+    lua_newtable(L);
398
+
399
+    viewport_t *a = first_screen_viewport;
400
+
401
+    if (!a)
402
+        return 1;
403
+
404
+    int count = 1;
405
+
406
+    do {
407
+        lua_newtable(L);
408
+
409
+        /* The geometry */
410
+        lua_pushstring(L, "geometry");
411
+
412
+        lua_newtable(L);
413
+
414
+        lua_pushstring(L, "x");
415
+        lua_pushinteger(L, a->x);
416
+        lua_settable(L, -3);
417
+        lua_pushstring(L, "y");
418
+        lua_pushinteger(L, a->y);
419
+        lua_settable(L, -3);
420
+        lua_pushstring(L, "width");
421
+        lua_pushinteger(L, a->width);
422
+        lua_settable(L, -3);
423
+        lua_pushstring(L, "height");
424
+        lua_pushinteger(L, a->height);
425
+        lua_settable(L, -3);
426
+
427
+        /* Add the geometry table to the arguments */
428
+        lua_settable(L, -3);
429
+
430
+        lua_rawseti(L, -2, count++);
431
+    } while ((a = a->next));
432
+
433
+    return 1;
434
+}
435
+
436
+/* Give Lua a chance to handle or blacklist a viewport before creating the
437
+ * screen object.
438
+ */
439
+static void
440
+viewports_notify(lua_State *L)
441
+{
442
+    if (!first_screen_viewport)
443
+        return;
444
+
445
+    luaA_viewports(L);
446
+
447
+    luaA_class_emit_signal(L, &screen_class, "property::viewports", 1);
448
+}
449
+
450
+static viewport_t *
451
+viewport_add(lua_State *L, int x, int y, int w, int h)
452
+{
453
+    /* Search existing to avoid having to deduplicate later */
454
+    viewport_t *a = first_screen_viewport;
455
+
456
+
457
+    do
458
+    {
459
+        if (a && a->x == x && a->y == y && a->width == w && a->height == h)
460
+        {
461
+            a->marked = true;
462
+            return a;
463
+        }
464
+    } while (a && (a = a->next));
465
+
466
+    viewport_t *node = malloc(sizeof(viewport_t));
467
+    node->x      = x;
468
+    node->y      = y;
469
+    node->width  = w;
470
+    node->height = h;
471
+    node->next   = NULL;
472
+    node->screen = NULL;
473
+    node->marked = true;
474
+
475
+    if (!first_screen_viewport) {
476
+        first_screen_viewport = node;
477
+        last_screen_viewport  = node;
478
+    } else {
479
+        last_screen_viewport->next = node;
480
+        last_screen_viewport = node;
481
+    }
482
+
483
+    assert(first_screen_viewport && last_screen_viewport);
484
+
485
+    return node;
486
+}
487
+
488
+static void
489
+monitor_unmark(void)
490
+{
491
+    viewport_t *a = first_screen_viewport;
492
+
493
+    if (!a)
494
+        return;
495
+
496
+    do
497
+    {
498
+        a->marked = false;
499
+    } while((a = a->next));
500
+}
501
+
502
+
503
+static void
504
+viewport_purge(void)
505
+{
506
+    viewport_t *cur = first_screen_viewport;
507
+
508
+    /* Move the head of the list */
509
+    while (first_screen_viewport && !first_screen_viewport->marked) {
510
+        cur = first_screen_viewport;
511
+        first_screen_viewport = cur->next;
512
+        free(cur);
513
+    }
514
+
515
+    if (!first_screen_viewport) {
516
+        last_screen_viewport = NULL;
517
+        return;
518
+    }
519
+
520
+    cur = first_screen_viewport;
521
+
522
+    /* Drop unmarked entries */
523
+    do {
524
+        if (cur->next && !cur->next->marked) {
525
+            viewport_t *tmp = cur->next;
526
+            cur->next = cur->next->next;
527
+
528
+            if (tmp == last_screen_viewport)
529
+                last_screen_viewport = cur;
530
+
531
+            free(tmp);
532
+        } else
533
+            cur = cur->next;
534
+
535
+    } while(cur);
536
+}
537
+
300 538
 static screen_t *
301 539
 screen_add(lua_State *L, screen_array_t *screens)
302 540
 {
@@ -333,7 +571,18 @@ screen_scan_randr_monitors(lua_State *L, screen_array_t *screens)
333 571
         if(!xcb_randr_monitor_info_outputs_length(monitor_iter.data))
334 572
             continue;
335 573
 
574
+        viewport_t *viewport = viewport_add(L,
575
+            monitor_iter.data->x,
576
+            monitor_iter.data->y,
577
+            monitor_iter.data->width,
578
+            monitor_iter.data->height
579
+        );
580
+
581
+        if (globalconf.ignore_screens)
582
+            continue;
583
+
336 584
         new_screen = screen_add(L, screens);
585
+        viewport->screen = new_screen;
337 586
         new_screen->geometry.x = monitor_iter.data->x;
338 587
         new_screen->geometry.y = monitor_iter.data->y;
339 588
         new_screen->geometry.width = monitor_iter.data->width;
@@ -355,9 +604,11 @@ screen_scan_randr_monitors(lua_State *L, screen_array_t *screens)
355 604
         } else {
356 605
             output.name = a_strdup("unknown");
357 606
         }
607
+
358 608
         randr_output_array_init(&output.outputs);
359 609
 
360 610
         randr_outputs = xcb_randr_monitor_info_outputs(monitor_iter.data);
611
+
361 612
         for(int i = 0; i < xcb_randr_monitor_info_outputs_length(monitor_iter.data); i++) {
362 613
             randr_output_array_append(&output.outputs, randr_outputs[i]);
363 614
         }
@@ -406,8 +657,22 @@ screen_scan_randr_crtcs(lua_State *L, screen_array_t *screens)
406 657
         if(!xcb_randr_get_crtc_info_outputs_length(crtc_info_r))
407 658
             continue;
408 659
 
660
+        viewport_t *viewport = viewport_add(L,
661
+            crtc_info_r->x,
662
+            crtc_info_r->y,
663
+            crtc_info_r->width,
664
+            crtc_info_r->height
665
+        );
666
+
667
+        if (globalconf.ignore_screens)
668
+        {
669
+            p_delete(&crtc_info_r);
670
+            continue;
671
+        }
672
+
409 673
         /* Prepare the new screen */
410 674
         screen_t *new_screen = screen_add(L, screens);
675
+        viewport->screen = new_screen;
411 676
         new_screen->geometry.x = crtc_info_r->x;
412 677
         new_screen->geometry.y = crtc_info_r->y;
413 678
         new_screen->geometry.width= crtc_info_r->width;
@@ -485,6 +750,7 @@ screen_scan_randr(lua_State *L, screen_array_t *screens)
485 750
     if(!version_reply)
486 751
         return;
487 752
 
753
+
488 754
     major_version = version_reply->major_version;
489 755
     minor_version = version_reply->minor_version;
490 756
     p_delete(&version_reply);
@@ -510,7 +776,7 @@ screen_scan_randr(lua_State *L, screen_array_t *screens)
510 776
     else
511 777
         screen_scan_randr_crtcs(L, screens);
512 778
 
513
-    if (screens->len == 0)
779
+    if (screens->len == 0 && !globalconf.ignore_screens)
514 780
     {
515 781
         /* Scanning failed, disable randr again */
516 782
         xcb_randr_select_input(globalconf.connection,
@@ -556,7 +822,18 @@ screen_scan_xinerama(lua_State *L, screen_array_t *screens)
556 822
 
557 823
     for(int screen = 0; screen < xinerama_screen_number; screen++)
558 824
     {
825
+        viewport_t *viewport = viewport_add(L,
826
+            xsi[screen].x_org,
827
+            xsi[screen].y_org,
828
+            xsi[screen].width,
829
+            xsi[screen].height
830
+        );
831
+
832
+        if (globalconf.ignore_screens)
833
+            continue;
834
+
559 835
         screen_t *s = screen_add(L, screens);
836
+        viewport->screen = s;
560 837
         s->geometry.x = xsi[screen].x_org;
561 838
         s->geometry.y = xsi[screen].y_org;
562 839
         s->geometry.width = xsi[screen].width;
@@ -569,7 +846,19 @@ screen_scan_xinerama(lua_State *L, screen_array_t *screens)
569 846
 static void screen_scan_x11(lua_State *L, screen_array_t *screens)
570 847
 {
571 848
     xcb_screen_t *xcb_screen = globalconf.screen;
849
+
850
+    viewport_t *viewport = viewport_add(L,
851
+        0,
852
+        0,
853
+        xcb_screen->width_in_pixels,
854
+        xcb_screen->height_in_pixels
855
+    );
856
+
857
+    if (globalconf.ignore_screens)
858
+        return;
859
+
572 860
     screen_t *s = screen_add(L, screens);
861
+    viewport->screen = s;
573 862
     s->geometry.x = 0;
574 863
     s->geometry.y = 0;
575 864
     s->geometry.width = xcb_screen->width_in_pixels;
@@ -586,21 +875,36 @@ screen_added(lua_State *L, screen_t *screen)
586 875
     lua_pop(L, 1);
587 876
 }
588 877
 
589
-/** Get screens informations and fill global configuration.
590
- */
591 878
 void
592
-screen_scan(void)
879
+screen_emit_scanned(void)
880
+{
881
+    lua_State *L = globalconf_get_lua_State();
882
+    luaA_class_emit_signal(L, &screen_class, "scanned", 0);
883
+}
884
+
885
+void
886
+screen_emit_scanning(void)
887
+{
888
+    lua_State *L = globalconf_get_lua_State();
889
+    luaA_class_emit_signal(L, &screen_class, "scanning", 0);
890
+}
891
+
892
+static void
893
+screen_scan_common(bool quiet)
593 894
 {
594 895
     lua_State *L;
595 896
 
596 897
     L = globalconf_get_lua_State();
597 898
 
899
+    monitor_unmark();
900
+
598 901
     screen_scan_randr(L, &globalconf.screens);
599 902
     if (globalconf.screens.len == 0)
600 903
         screen_scan_xinerama(L, &globalconf.screens);
601 904
     if (globalconf.screens.len == 0)
602 905
         screen_scan_x11(L, &globalconf.screens);
603
-    check(globalconf.screens.len > 0);
906
+
907
+    check(globalconf.screens.len > 0 || globalconf.ignore_screens);
604 908
 
605 909
     screen_deduplicate(L, &globalconf.screens);
606 910
 
@@ -608,9 +912,30 @@ screen_scan(void)
608 912
         screen_added(L, *screen);
609 913
     }
610 914
 
915
+    viewport_purge();
916
+
917
+    if (!quiet)
918
+        viewports_notify(L);
919
+
611 920
     screen_update_primary();
612 921
 }
613 922
 
923
+/** Get screens informations and fill global configuration.
924
+ */
925
+void
926
+screen_scan(void)
927
+{
928
+    screen_emit_scanning();
929
+    screen_scan_common(false);
930
+}
931
+
932
+static int
933
+luaA_scan_quiet(lua_State *L)
934
+{
935
+    screen_scan_common(true);
936
+    return 0;
937
+}
938
+
614 939
 /* Called when a screen is removed, removes references to the old screen */
615 940
 static void
616 941
 screen_removed(lua_State *L, int sidx)
@@ -671,6 +996,8 @@ screen_refresh(gpointer unused)
671 996
 {
672 997
     globalconf.screen_refresh_pending = false;
673 998
 
999
+    monitor_unmark();
1000
+
674 1001
     screen_array_t new_screens;
675 1002
     screen_array_t removed_screens;
676 1003
     lua_State *L = globalconf_get_lua_State();
@@ -682,6 +1009,10 @@ screen_refresh(gpointer unused)
682 1009
     else
683 1010
         screen_scan_randr_crtcs(L, &new_screens);
684 1011
 
1012
+    viewport_purge();
1013
+
1014
+    viewports_notify(L);
1015
+
685 1016
     screen_deduplicate(L, &new_screens);
686 1017
 
687 1018
     /* Running without any screens at all is no fun. */
@@ -837,10 +1168,10 @@ screen_coord_in_screen(screen_t *s, int x, int y)
837 1168
 bool
838 1169
 screen_area_in_screen(screen_t *s, area_t geom)
839 1170
 {
840
-        return (geom.x < s->geometry.x + s->geometry.width)
841
-               && (geom.x + geom.width > s->geometry.x )
842
-               && (geom.y < s->geometry.y + s->geometry.height)
843
-               && (geom.y + geom.height > s->geometry.y);
1171
+    return (geom.x < s->geometry.x + s->geometry.width)
1172
+            && (geom.x + geom.width > s->geometry.x )
1173
+            && (geom.y < s->geometry.y + s->geometry.height)
1174
+            && (geom.y + geom.height > s->geometry.y);
844 1175
 }
845 1176
 
846 1177
 void screen_update_workarea(screen_t *screen)
@@ -1077,6 +1408,11 @@ luaA_screen_module_index(lua_State *L)
1077 1408
     {
1078 1409
         if(A_STREQ(name, "primary"))
1079 1410
             return luaA_object_push(L, screen_get_primary());
1411
+        else if (A_STREQ(name, "automatic_factory"))
1412
+        {
1413
+            lua_pushboolean(L, !globalconf.ignore_screens);
1414
+            return 1;
1415
+        }
1080 1416
 
1081 1417
         foreach(screen, globalconf.screens)
1082 1418
             foreach(output, (*screen)->outputs)
@@ -1090,6 +1426,28 @@ luaA_screen_module_index(lua_State *L)
1090 1426
     return luaA_object_push(L, luaA_checkscreen(L, 2));
1091 1427
 }
1092 1428
 
1429
+static int
1430
+luaA_screen_module_newindex(lua_State *L)
1431
+{
1432
+    const char *buf = luaL_checkstring(L, 2);
1433
+
1434
+    if (A_STREQ(buf, "automatic_factory"))
1435
+    {
1436
+        globalconf.ignore_screens = !luaA_checkboolean(L, 3);
1437
+
1438
+        /* It *can* be useful if screens are added/removed later, but generally,
1439
+         * setting this should be done before screens are added
1440
+         */
1441
+        if (globalconf.ignore_screens && !globalconf.no_auto_screen)
1442
+            luaA_warn(L,
1443
+                "Setting automatic_factory only makes sense when AwesomeWM is"
1444
+                " started with `--screen off`"
1445
+            );
1446
+    }
1447
+
1448
+    return luaA_default_newindex(L);
1449
+}
1450
+
1093 1451
 /** Iterate over screens.
1094 1452
  * @usage
1095 1453
  * for s in screen do
@@ -1312,8 +1670,10 @@ screen_class_setup(lua_State *L)
1312 1670
     {
1313 1671
         LUA_CLASS_METHODS(screen)
1314 1672
         { "count", luaA_screen_count },
1673
+        { "_viewports", luaA_viewports },
1674
+        { "_scan_quiet", luaA_scan_quiet },
1315 1675
         { "__index", luaA_screen_module_index },
1316
-        { "__newindex", luaA_default_newindex },
1676
+        { "__newindex", luaA_screen_module_newindex },
1317 1677
         { "__call", luaA_screen_module_call },
1318 1678
         { "fake_add", luaA_screen_fake_add },
1319 1679
         { NULL, NULL }

+ 2
- 0
objects/screen.h View File

@@ -57,6 +57,8 @@ void screen_update_primary(void);
57 57
 void screen_update_workarea(screen_t *);
58 58
 screen_t *screen_get_primary(void);
59 59
 void screen_schedule_refresh(void);
60
+void screen_emit_scanned(void);
61
+void screen_emit_scanning(void);
60 62
 
61 63
 screen_t *luaA_checkscreen(lua_State *, int);
62 64
 

Loading…
Cancel
Save