app: Allow to place the window on a different output
[apps/hvac.git] / app / main.cpp
1 /*
2  * Copyright (C) 2016 The Qt Company Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <QtGui/QGuiApplication>
18 #include <QDebug>
19 #include <QUrlQuery>
20 #include <QCommandLineParser>
21 #include <QtQml/QQmlApplicationEngine>
22 #include <QtQml/QQmlContext>
23 #include <QScreen>
24
25 #include <qpa/qplatformnativeinterface.h>
26 #include <wayland-client.h>
27
28 #include "shell-desktop.h"
29 #include "wayland-agl-shell-desktop-client-protocol.h"
30
31 #include "translator.h"
32
33 /* this could be a combintion or some sort */
34 #define OUTPUT_ID       "Virtual-1"
35
36 static void
37 global_add(void *data, struct wl_registry *reg, uint32_t name,
38                 const char *interface, uint32_t)
39 {
40         struct agl_shell_desktop **shell = static_cast<struct agl_shell_desktop **>(data);
41
42         if (strcmp(interface, agl_shell_desktop_interface.name) == 0) {
43                 *shell = static_cast<struct agl_shell_desktop *>(
44                                 wl_registry_bind(reg, name, &agl_shell_desktop_interface, 1)
45                                 );
46         }
47 }
48
49 static void
50 global_remove(void *data, struct wl_registry *reg, uint32_t id)
51 {
52         /* Don't care */
53         (void) data;
54         (void) reg;
55         (void) id;
56 }
57
58 static const struct wl_registry_listener registry_listener = {
59         global_add,
60         global_remove,
61 };
62
63 static struct agl_shell_desktop *
64 register_agl_shell_desktop(QPlatformNativeInterface *native)
65 {
66         struct wl_display *wl;
67         struct wl_registry *registry;
68         struct agl_shell_desktop *shell = nullptr;
69
70         wl = static_cast<struct wl_display *>(native->nativeResourceForIntegration("display"));
71         registry = wl_display_get_registry(wl);
72
73         wl_registry_add_listener(registry, &registry_listener, &shell);
74
75         /* Roundtrip to get all globals advertised by the compositor */
76         wl_display_roundtrip(wl);
77         wl_registry_destroy(registry);
78
79         return shell;
80 }
81
82 static QScreen *
83 find_qscreen(const char *screen_name)
84 {
85         QList<QScreen *> screens = qApp->screens();
86         QScreen *found = nullptr;
87         QString qstr_name = QString::fromUtf8(screen_name, -1);
88
89         for (QScreen *xscreen : screens) {
90                 if (qstr_name == xscreen->name()) {
91                         found = xscreen;
92                         break;
93                 }
94         }
95
96         return found;
97 }
98
99
100 int main(int argc, char *argv[])
101 {
102         setenv("QT_QPA_PLATFORM", "wayland", 1);
103         int port;
104         QString token;
105         QString graphic_role = "hvac";
106         struct agl_shell_desktop *agl_shell_desktop = nullptr;
107
108         QCommandLineParser parser;
109         QGuiApplication app(argc, argv);
110         app.setDesktopFileName(graphic_role);
111
112         parser.addPositionalArgument("port",
113                 app.translate("main", "port for binding"));
114         parser.addPositionalArgument("secret",
115                 app.translate("main", "secret for binding"));
116
117         parser.addHelpOption();
118         parser.addVersionOption();
119         parser.process(app);
120         QStringList positionalArguments = parser.positionalArguments();
121
122         if (positionalArguments.length() == 2) {
123                 port = positionalArguments.takeFirst().toInt();
124                 token = positionalArguments.takeFirst();
125                 qInfo() << "setting port:" << port << ", token:" << token;
126         } else {
127                 qInfo() << "Need to specify port and token";
128                 exit(EXIT_FAILURE);
129         }
130
131         QPlatformNativeInterface *native = qApp->platformNativeInterface();
132         agl_shell_desktop = register_agl_shell_desktop(native);
133         if (!agl_shell_desktop) {
134                 qDebug() << "Could not find agl_shell_desktop extension. Is agl-compositor running?";
135                 exit(EXIT_FAILURE);
136         }
137
138         std::shared_ptr<struct agl_shell_desktop> shell{agl_shell_desktop, agl_shell_desktop_destroy};
139         Shell *aglShell = new Shell(shell, nullptr);
140
141         QScreen *screen_to_put = find_qscreen(OUTPUT_ID);
142         if (screen_to_put)
143                 aglShell->set_window_on_screen(screen_to_put, graphic_role);
144
145         QUrl bindingAddress;
146         bindingAddress.setScheme(QStringLiteral("ws"));
147         bindingAddress.setHost(QStringLiteral("localhost"));
148         bindingAddress.setPort(port);
149         bindingAddress.setPath(QStringLiteral("/api"));
150
151         QUrlQuery query;
152         query.addQueryItem(QStringLiteral("token"), token);
153         bindingAddress.setQuery(query);
154
155         QQmlApplicationEngine engine;
156         engine.rootContext()->setContextProperty("bindingAddress", bindingAddress);
157         qmlRegisterType<Translator>("Translator", 1, 0, "Translator");
158         engine.load(QUrl(QStringLiteral("qrc:/HVAC.qml")));
159
160         return app.exec();
161 }