blob: f71c9f13d9e8c9b125eca3e0899a5f97e7e68100 [file] [log] [blame]
/*
* BRLTTY - A background process providing access to the console screen (when in
* text mode) for a blind person using a refreshable braille display.
*
* Copyright (C) 1995-2023 by The BRLTTY Developers.
*
* BRLTTY comes with ABSOLUTELY NO WARRANTY.
*
* This is free software, placed under the terms of the
* GNU Lesser General Public License, as published by the Free Software
* Foundation; either version 2.1 of the License, or (at your option) any
* later version. Please see the file LICENSE-LGPL for details.
*
* Web Page: http://brltty.app/
*
* This software is maintained by Dave Mielke <dave@mielke.cc>.
*/
#include "prologue.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "log.h"
#include "parameters.h"
#include "device.h"
#include "get_select.h"
#include "async_alarm.h"
#include "scr.h"
#include "scr_gpm.h"
#ifdef HAVE_LIBGPM
#include <gpm.h>
extern int gpm_tried;
typedef enum {
GCS_CLOSED,
GCS_FAILED,
GCS_OPENED
} GpmConnectionState;
static int gpmConnectionState = GCS_CLOSED;
ASYNC_ALARM_CALLBACK(gpmResetConnection) {
gpmConnectionState = GCS_CLOSED;
}
static int
gpmOpenConnection (void) {
switch (gpmConnectionState) {
case GCS_CLOSED: {
Gpm_Connect options = {
.eventMask = GPM_MOVE,
.defaultMask = ~0,
.minMod = 0,
.maxMod = ~0
};
gpm_tried = 0;
gpm_zerobased = 1;
if (Gpm_Open(&options, -1) == -1) {
logMessage(LOG_DEBUG, "GPM open error: %s", strerror(errno));
asyncNewRelativeAlarm(NULL, GPM_CONNECTION_RESET_DELAY, gpmResetConnection, NULL);
gpmConnectionState = GCS_FAILED;
return 0;
}
logMessage(LOG_DEBUG, "GPM opened: fd=%d con=%d", gpm_fd, gpm_consolefd);
gpmConnectionState = GCS_OPENED;
}
case GCS_OPENED:
return 1;
}
return 0;
}
static void
gpmCloseConnection (int alreadyClosed) {
if (gpmConnectionState == GCS_OPENED) {
if (!alreadyClosed) Gpm_Close();
logMessage(LOG_DEBUG, "GPM closed");
}
gpmConnectionState = GCS_CLOSED;
}
#endif /* HAVE_LIBGPM */
static int
gpmScreenHandler_highlightRegion (int left, int right, int top, int bottom) {
#ifdef HAVE_LIBGPM
FILE *console = getConsole();
if (console) {
if (gpmOpenConnection() && (gpm_fd >= 0)) {
if (Gpm_DrawPointer(left, top, fileno(console)) != -1) return 1;
if (errno != EINVAL) {
logMessage(LOG_DEBUG, "Gpm_DrawPointer error: %s", strerror(errno));
gpmCloseConnection(0);
return 0;
}
}
}
#endif /* HAVE_LIBGPM */
return 0;
}
static int
gpmScreenHandler_getPointer (int *column, int *row) {
int ok = 0;
#ifdef HAVE_LIBGPM
if (gpmOpenConnection()) {
if (gpm_fd >= 0) {
int error = 0;
while (1) {
fd_set mask;
struct timeval timeout;
Gpm_Event event;
int result;
FD_ZERO(&mask);
FD_SET(gpm_fd, &mask);
memset(&timeout, 0, sizeof(timeout));
if ((result = select(gpm_fd+1, &mask, NULL, NULL, &timeout)) == 0) break;
error = 1;
if (result == -1) {
if (errno == EINTR) continue;
logSystemError("select");
break;
}
if (!FD_ISSET(gpm_fd, &mask)) {
logMessage(LOG_DEBUG, "GPM file descriptor not set: %d", gpm_fd);
break;
}
if ((result = Gpm_GetEvent(&event)) == -1) {
if (errno == EINTR) continue;
logSystemError("Gpm_GetEvent");
break;
}
error = 0;
if (result == 0) {
gpmCloseConnection(1);
break;
}
*column = event.x;
*row = event.y;
ok = 1;
}
if (error) gpmCloseConnection(0);
}
}
#endif /* HAVE_LIBGPM */
return ok;
}
void
gpmIncludeScreenHandlers (MainScreen *main) {
main->base.highlightRegion = gpmScreenHandler_highlightRegion;
main->base.getPointer = gpmScreenHandler_getPointer;
}