1777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine/* Copyright (C) 2010 The Android Open Source Project
2777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine**
3777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine** This software is licensed under the terms of the GNU General Public
4777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine** License version 2, as published by the Free Software Foundation, and
5777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine** may be copied, distributed, and modified under those terms.
6777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine**
7777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine** This program is distributed in the hope that it will be useful,
8777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine** but WITHOUT ANY WARRANTY; without even the implied warranty of
9777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine** GNU General Public License for more details.
11777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine*/
12777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
13777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine/*
14777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine * Contains the Core-side implementation of the "core-ui-control" service that is
15777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine * part of the UI control protocol. Here we send UI control commands to the UI.
16777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine */
17777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
18777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine#include "android/android.h"
19777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine#include "android/hw-control.h"
20777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine#include "android/looper.h"
21777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine#include "android/async-utils.h"
22777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine#include "android/sync-utils.h"
23777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine#include "android/utils/debug.h"
24777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine#include "android/protocol/ui-commands.h"
25777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine#include "android/protocol/ui-commands-proxy.h"
26777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine#include "android/protocol/ui-commands-api.h"
27777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
28777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine/* Descriptor for the UI commands proxy. */
29777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkinetypedef struct UICmdProxy {
30777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    /* I/O associated with this descriptor. */
31777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    LoopIo          io;
32777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
33777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    /* Looper associated with this descriptor. */
34777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    Looper*         looper;
35777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
36777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    /* Writer to send UI commands. */
37777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    SyncSocket*     sync_writer;
38777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
39777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    /* Socket descriptor for this service. */
40777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    int             sock;
41777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine} UICmdProxy;
42777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
43777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine/* One and only one UICmdProxy instance. */
44777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkinestatic UICmdProxy    _uiCmdProxy;
45777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
46777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine/* Implemented in android/console.c */
47777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkineextern void destroy_uicmd_client(void);
48777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
49777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine/* Calculates timeout for transferring the given number of bytes via socket.
50777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine * Return:
51777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine *  Number of milliseconds during which the entire number of bytes is expected
52777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine *  to be transferred via socket.
53777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine */
54777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkinestatic int
55777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine_uiCmdProxy_get_timeout(size_t data_size)
56777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine{
57777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    // Min 2 seconds + 10 millisec for each transferring byte.
58777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    // TODO: Come up with a better arithmetics here.
59777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    return 2000 + data_size * 10;
60777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine}
61777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
62777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine/* Sends request to the UI client of this service.
63777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine * Param:
64777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine *  cmd_type, cmd_param, cmd_param_size - Define the command to send.
65777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine * Return:
66777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine *  0 on success, or < 0 on failure.
67777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine */
68777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkinestatic int
69777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine_uiCmdProxy_send_command(uint8_t cmd_type,
70777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine                         void* cmd_param,
71777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine                         uint32_t cmd_param_size)
72777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine{
73777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    UICmdHeader header;
74777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    int status = syncsocket_start_write(_uiCmdProxy.sync_writer);
75777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    if (!status) {
76777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        // Initialize and send the header.
77777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        header.cmd_type = cmd_type;
78777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        header.cmd_param_size = cmd_param_size;
79777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        status = syncsocket_write(_uiCmdProxy.sync_writer, &header, sizeof(header),
80777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine                                  _uiCmdProxy_get_timeout(sizeof(header)));
81777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        // If there are command parameters, send them too.
82777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        if (status > 0 && cmd_param != NULL && cmd_param_size > 0) {
83777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine            status = syncsocket_write(_uiCmdProxy.sync_writer, cmd_param,
84777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine                                      cmd_param_size,
85777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine                                      _uiCmdProxy_get_timeout(cmd_param_size));
86777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        }
87777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        status = syncsocket_result(status);
88777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        syncsocket_stop_write(_uiCmdProxy.sync_writer);
89777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    }
90777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    if (status < 0) {
91777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        derror("Send UI command %d (%u bytes) has failed: %s\n",
92777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine               cmd_type, cmd_param_size, errno_str);
93777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    }
94777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    return status;
95777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine}
96777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
97777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine/* Asynchronous I/O callback for UICmdProxy instance.
98777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine * We expect this callback to be called only on UI detachment condition. In this
99777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine * case the event should be LOOP_IO_READ, and read should fail with errno set
100777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine * to ECONNRESET.
101777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine * Param:
102777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine *  opaque - UICmdProxy instance.
103777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine */
104777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkinestatic void
105777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine_uiCmdProxy_io_func(void* opaque, int fd, unsigned events)
106777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine{
107777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    UICmdProxy* uicmd = (UICmdProxy*)opaque;
108777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    AsyncReader reader;
109777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    AsyncStatus status;
110777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    uint8_t read_buf[1];
111777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
112777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    if (events & LOOP_IO_WRITE) {
113777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        derror("Unexpected LOOP_IO_WRITE in _uiCmdProxy_io_func.\n");
114777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        return;
115777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    }
116777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
117777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    // Try to read
118777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    asyncReader_init(&reader, read_buf, sizeof(read_buf), &uicmd->io);
119f9e333ade2529f257ced6bcff8e5824cb07eacf9David 'Digit' Turner    status = asyncReader_read(&reader);
120777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    // We expect only error status here.
121777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    if (status != ASYNC_ERROR) {
122777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        derror("Unexpected read status %d in _uiCmdProxy_io_func\n", status);
123777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        return;
124777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    }
125777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    // We expect only socket disconnection error here.
126777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    if (errno != ECONNRESET) {
127777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        derror("Unexpected read error %d (%s) in _uiCmdProxy_io_func.\n",
128777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine               errno, errno_str);
129777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        return;
130777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    }
131777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
132777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    // Client got disconnectted.
133777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    destroy_uicmd_client();
134777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine}
135777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine/* a callback function called when the system wants to change the brightness
136777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine * of a given light. 'light' is a string which can be one of:
137777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine * 'lcd_backlight', 'button_backlight' or 'Keyboard_backlight'
138777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine *
139777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine * brightness is an integer (acceptable range are 0..255), however the
140777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine * default is around 105, and we probably don't want to dim the emulator's
141777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine * output at that level.
142777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine */
143777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkinestatic void
144777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine_uiCmdProxy_brightness_change_callback(void* opaque,
145777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine                                       const char* light,
146777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine                                       int brightness)
147777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine{
148777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    // Calculate size of the command parameters.
149777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    const size_t cmd_size = sizeof(UICmdChangeDispBrightness) + strlen(light) + 1;
150777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    // Allocate and initialize parameters.
151777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    UICmdChangeDispBrightness* cmd =
152777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        (UICmdChangeDispBrightness*)qemu_malloc(cmd_size);
153777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    cmd->brightness = brightness;
154777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    strcpy(cmd->light, light);
155777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    // Send the command.
156777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    _uiCmdProxy_send_command(AUICMD_CHANGE_DISP_BRIGHTNESS, cmd, cmd_size);
157777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    qemu_free(cmd);
158777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine}
159777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
160777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkineint
161777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir ChtchetkineuiCmdProxy_create(int fd)
162777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine{
163777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    // Initialize the only UICmdProxy instance.
164777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    _uiCmdProxy.sock = fd;
165777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    _uiCmdProxy.looper = looper_newCore();
166777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    loopIo_init(&_uiCmdProxy.io, _uiCmdProxy.looper, _uiCmdProxy.sock,
167777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine                _uiCmdProxy_io_func, &_uiCmdProxy);
168777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    loopIo_wantRead(&_uiCmdProxy.io);
169777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    _uiCmdProxy.sync_writer = syncsocket_init(fd);
170777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    if (_uiCmdProxy.sync_writer == NULL) {
171777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        derror("Unable to initialize UICmdProxy writer: %s\n", errno_str);
172777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        uiCmdProxy_destroy();
173777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        return -1;
174777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    }
175777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    {
176777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        // Set brighness change callback, so we can notify
177777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        // the UI about the event.
178777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        AndroidHwControlFuncs  funcs;
179777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        funcs.light_brightness = _uiCmdProxy_brightness_change_callback;
180ca9505992288636908169d0389087b3ca5277d07David 'Digit' Turner        android_hw_control_set(&_uiCmdProxy, &funcs);
181777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    }
182777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    return 0;
183777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine}
184777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
185777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkinevoid
186777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir ChtchetkineuiCmdProxy_destroy()
187777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine{
188777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    // Destroy the sync writer.
189777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    if (_uiCmdProxy.sync_writer != NULL) {
190777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        syncsocket_close(_uiCmdProxy.sync_writer);
191777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        syncsocket_free(_uiCmdProxy.sync_writer);
192777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    }
193777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    if (_uiCmdProxy.looper != NULL) {
194777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        // Stop all I/O that may still be going on.
195777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        loopIo_done(&_uiCmdProxy.io);
196777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        looper_free(_uiCmdProxy.looper);
197777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine        _uiCmdProxy.looper = NULL;
198777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    }
199777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    _uiCmdProxy.sock = -1;
200777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine}
201777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine
202777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkineint
203777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkineuicmd_set_window_scale(double scale, int is_dpi)
204777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine{
205777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    UICmdSetWindowsScale cmd;
206777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    cmd.scale = scale;
207777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    cmd.is_dpi = is_dpi;
208777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine    return _uiCmdProxy_send_command(AUICMD_SET_WINDOWS_SCALE, &cmd, sizeof(cmd));
209777eb68eb60cac18f4b62e2e1b14a906875cbe7aVladimir Chtchetkine}
210