Finish multi-monitor support
This commit is contained in:
@@ -162,6 +162,7 @@ int postcard_enabled = 0; /* (C) enable POST card */
|
||||
int isamem_type[ISAMEM_MAX] = { 0,0,0,0 }; /* (C) enable ISA mem cards */
|
||||
int isartc_type = 0; /* (C) enable ISA RTC card */
|
||||
int gfxcard = 0; /* (C) graphics/video card */
|
||||
int gfxcard_2 = 0; /* (C) graphics/video card */
|
||||
int sound_is_float = 1; /* (C) sound uses FP values */
|
||||
int GAMEBLASTER = 0; /* (C) sound option */
|
||||
int GUS = 0; /* (C) sound option */
|
||||
|
||||
10
src/config.c
10
src/config.c
@@ -926,7 +926,9 @@ load_video(void)
|
||||
voodoo_enabled = !!config_get_int(cat, "voodoo", 0);
|
||||
ibm8514_enabled = !!config_get_int(cat, "8514a", 0);
|
||||
xga_enabled = !!config_get_int(cat, "xga", 0);
|
||||
herc_enabled = !!config_get_int(cat, "herc_enabled", 0);
|
||||
p = config_get_string(cat, "gfxcard_2", NULL);
|
||||
if (!p) p = "none";
|
||||
gfxcard_2 = video_get_video_from_internal_name(p);
|
||||
}
|
||||
|
||||
|
||||
@@ -2512,10 +2514,10 @@ save_video(void)
|
||||
else
|
||||
config_set_int(cat, "xga", xga_enabled);
|
||||
|
||||
if (herc_enabled == 0)
|
||||
config_delete_var(cat, "herc_enabled");
|
||||
if (gfxcard_2 == 0)
|
||||
config_delete_var(cat, "gfxcard_2");
|
||||
else
|
||||
config_set_int(cat, "herc_enabled", herc_enabled);
|
||||
config_set_string(cat, "gfxcard_2", video_get_internal_name(gfxcard_2));
|
||||
|
||||
delete_section_if_empty(cat);
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ extern monitor_t monitors[MONITORS_NUM];
|
||||
extern monitor_settings_t monitor_settings[MONITORS_NUM];
|
||||
extern atomic_bool doresize_monitors[MONITORS_NUM];
|
||||
extern int monitor_index_global;
|
||||
extern int herc_enabled;
|
||||
extern int gfxcard_2;
|
||||
|
||||
typedef rgb_t PALETTE[256];
|
||||
|
||||
@@ -219,6 +219,7 @@ extern const device_t *video_card_getdevice(int card);
|
||||
extern int video_card_has_config(int card);
|
||||
extern char *video_get_internal_name(int card);
|
||||
extern int video_get_video_from_internal_name(char *s);
|
||||
extern int video_card_get_flags(int card);
|
||||
extern int video_is_mda(void);
|
||||
extern int video_is_cga(void);
|
||||
extern int video_is_ega_vga(void);
|
||||
|
||||
@@ -622,8 +622,8 @@ MainWindow::~MainWindow() {
|
||||
void MainWindow::showEvent(QShowEvent *event) {
|
||||
if (shownonce) return;
|
||||
shownonce = true;
|
||||
if (window_remember) resize(window_w, window_h + menuBar()->height() + (hide_status_bar ? 0 : statusBar()->height()) + (hide_tool_bar ? 0 : ui->toolBar->height()));
|
||||
if (window_remember && !QApplication::platformName().contains("wayland")) {
|
||||
fprintf(stderr, "Geom: %i, %i, %i, %i\n", window_x, window_y, window_w, window_h);
|
||||
setGeometry(window_x, window_y, window_w, window_h + menuBar()->height() + (hide_status_bar ? 0 : statusBar()->height()) + (hide_tool_bar ? 0 : ui->toolBar->height()));
|
||||
}
|
||||
if (vid_resize == 2) {
|
||||
@@ -1991,8 +1991,13 @@ void MainWindow::on_actionRenderer_options_triggered()
|
||||
{
|
||||
auto dlg = ui->stackedWidget->getOptions(this);
|
||||
|
||||
if (dlg)
|
||||
dlg->exec();
|
||||
if (dlg) {
|
||||
if (dlg->exec() == QDialog::Accepted) {
|
||||
for (int i = 1; i < MONITORS_NUM; i++) {
|
||||
if (renderers[i] && renderers[i]->hasOptions()) renderers[i]->reloadOptions();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionMCA_devices_triggered()
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
OpenGLRenderer::OpenGLRenderer(QWidget *parent)
|
||||
: QWindow(parent->windowHandle())
|
||||
, renderTimer(new QTimer(this))
|
||||
, options(nullptr)
|
||||
{
|
||||
renderTimer->setTimerType(Qt::PreciseTimer);
|
||||
/* TODO: need's more accuracy, maybe target 1ms earlier and spin yield */
|
||||
@@ -165,9 +166,7 @@ OpenGLRenderer::initialize()
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, QOpenGLTexture::RGBA8_UNorm, INIT_WIDTH, INIT_HEIGHT, 0, QOpenGLTexture::BGRA, QOpenGLTexture::UInt32_RGBA8_Rev, NULL);
|
||||
|
||||
options = new OpenGLOptions(this, true, glslVersion);
|
||||
|
||||
applyOptions();
|
||||
reloadOptions();
|
||||
|
||||
glClearColor(0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
@@ -304,6 +303,15 @@ OpenGLRenderer::applyOptions()
|
||||
currentFilter = options->filter();
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRenderer::reloadOptions()
|
||||
{
|
||||
if (options) { delete options; options = nullptr; }
|
||||
options = new OpenGLOptions(this, true, glslVersion);
|
||||
|
||||
applyOptions();
|
||||
}
|
||||
|
||||
void
|
||||
OpenGLRenderer::applyShader(const OpenGLShaderPass &shader)
|
||||
{
|
||||
|
||||
@@ -53,6 +53,7 @@ public:
|
||||
void finalize() override final;
|
||||
bool hasOptions() const override { return true; }
|
||||
QDialog *getOptions(QWidget *parent) override;
|
||||
void reloadOptions() override;
|
||||
|
||||
signals:
|
||||
void initialized();
|
||||
|
||||
@@ -28,6 +28,8 @@ public:
|
||||
virtual bool hasOptions() const { return false; }
|
||||
/* Returns options dialog for renderer */
|
||||
virtual QDialog *getOptions(QWidget *parent) { return nullptr; }
|
||||
/* Reloads options of renderer */
|
||||
virtual void reloadOptions() {}
|
||||
|
||||
virtual bool hasBlitFunc() { return false; }
|
||||
virtual void blit(int x, int y, int w, int h) {}
|
||||
|
||||
@@ -53,6 +53,8 @@ public:
|
||||
|
||||
/* Does current renderer implement options dialog */
|
||||
bool hasOptions() const { return rendererWindow ? rendererWindow->hasOptions() : false; }
|
||||
/* Reloads options of current renderer */
|
||||
void reloadOptions() const { return rendererWindow->reloadOptions(); }
|
||||
/* Returns options dialog for current renderer */
|
||||
QDialog *getOptions(QWidget *parent) { return rendererWindow ? rendererWindow->getOptions(parent) : nullptr; }
|
||||
|
||||
|
||||
@@ -87,9 +87,13 @@ void SettingsDisplay::onCurrentMachineChanged(int machineId) {
|
||||
|
||||
if (machine_has_flags(machineId, MACHINE_VIDEO_ONLY) > 0) {
|
||||
ui->comboBoxVideo->setEnabled(false);
|
||||
ui->comboBoxVideoSecondary->setEnabled(false);
|
||||
ui->pushButtonConfigureSecondary->setEnabled(false);
|
||||
selectedRow = 1;
|
||||
} else {
|
||||
ui->comboBoxVideo->setEnabled(true);
|
||||
ui->comboBoxVideoSecondary->setEnabled(true);
|
||||
ui->pushButtonConfigureSecondary->setEnabled(true);
|
||||
}
|
||||
ui->comboBoxVideo->setCurrentIndex(selectedRow);
|
||||
}
|
||||
@@ -137,6 +141,30 @@ void SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index) {
|
||||
ui->checkBoxXga->setChecked(xga_enabled);
|
||||
|
||||
ui->pushButtonConfigureXga->setEnabled((hasIsa16 || has_MCA) && ui->checkBoxXga->isChecked());
|
||||
|
||||
int c = 2;
|
||||
ui->comboBoxVideoSecondary->clear();
|
||||
ui->comboBoxVideoSecondary->addItem(QObject::tr("None"), 0);
|
||||
|
||||
while (true) {
|
||||
const device_t* video_dev = video_card_getdevice(c);
|
||||
QString name = DeviceConfig::DeviceName(video_dev, video_get_internal_name(c), 1);
|
||||
if (name.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (video_card_available(c) &&
|
||||
device_is_valid(video_dev, machineId) &&
|
||||
!(video_card_get_flags(c) == video_card_get_flags(videoCard))) {
|
||||
ui->comboBoxVideoSecondary->addItem(name, c);
|
||||
if (c == gfxcard_2)
|
||||
ui->comboBoxVideoSecondary->setCurrentIndex(ui->comboBoxVideoSecondary->count() - 1);
|
||||
}
|
||||
|
||||
c++;
|
||||
}
|
||||
|
||||
if (gfxcard_2 == 0 || (machine_has_flags(machineId, MACHINE_VIDEO_ONLY) > 0)) ui->comboBoxVideoSecondary->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
void SettingsDisplay::on_checkBoxVoodoo_stateChanged(int state) {
|
||||
@@ -146,3 +174,20 @@ void SettingsDisplay::on_checkBoxVoodoo_stateChanged(int state) {
|
||||
void SettingsDisplay::on_checkBoxXga_stateChanged(int state) {
|
||||
ui->pushButtonConfigureXga->setEnabled(state == Qt::Checked);
|
||||
}
|
||||
|
||||
void SettingsDisplay::on_comboBoxVideoSecondary_currentIndexChanged(int index)
|
||||
{
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
int videoCard = ui->comboBoxVideoSecondary->currentData().toInt();
|
||||
ui->pushButtonConfigureSecondary->setEnabled(video_card_has_config(videoCard) > 0);
|
||||
}
|
||||
|
||||
|
||||
void SettingsDisplay::on_pushButtonConfigureSecondary_clicked()
|
||||
{
|
||||
auto* device = video_card_getdevice(ui->comboBoxVideoSecondary->currentData().toInt());
|
||||
DeviceConfig::ConfigureDevice(device, 0, qobject_cast<Settings*>(Settings::settings));
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,12 @@ public:
|
||||
public slots:
|
||||
void onCurrentMachineChanged(int machineId);
|
||||
|
||||
private slots:
|
||||
void on_pushButtonConfigureSecondary_clicked();
|
||||
|
||||
private slots:
|
||||
void on_comboBoxVideoSecondary_currentIndexChanged(int index);
|
||||
|
||||
private slots:
|
||||
void on_checkBoxVoodoo_stateChanged(int state);
|
||||
void on_checkBoxXga_stateChanged(int state);
|
||||
|
||||
@@ -26,16 +26,29 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="comboBoxVideo"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="checkBox8514">
|
||||
<property name="text">
|
||||
<string>Video:</string>
|
||||
<string>8514/A</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="comboBoxVideo"/>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="pushButtonConfigure">
|
||||
<property name="sizePolicy">
|
||||
@@ -49,53 +62,57 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="pushButtonConfigureVoodoo">
|
||||
<property name="text">
|
||||
<string>Configure</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="checkBoxVoodoo">
|
||||
<property name="text">
|
||||
<string>Voodoo Graphics</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="checkBox8514">
|
||||
<property name="text">
|
||||
<string>8514/A</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QPushButton" name="pushButtonConfigureXga">
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="pushButtonConfigureVoodoo">
|
||||
<property name="text">
|
||||
<string>Configure</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Video:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="checkBoxXga">
|
||||
<property name="text">
|
||||
<string>XGA</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<item row="4" column="2">
|
||||
<widget class="QPushButton" name="pushButtonConfigureXga">
|
||||
<property name="text">
|
||||
<string>Configure</string>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Video #2:</string>
|
||||
</property>
|
||||
</spacer>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="comboBoxVideoSecondary"/>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="pushButtonConfigureSecondary">
|
||||
<property name="text">
|
||||
<string>Configure</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
@@ -82,12 +82,16 @@ typedef struct {
|
||||
int dispon, blink;
|
||||
int vsynctime;
|
||||
int vadj;
|
||||
int monitor_index, prev_monitor_index;
|
||||
|
||||
int cols[256][2][2];
|
||||
|
||||
uint8_t *vram;
|
||||
} herculesplus_t;
|
||||
|
||||
#define VIDEO_MONITOR_PROLOGUE() { dev->prev_monitor_index = monitor_index_global; monitor_index_global = dev->monitor_index; }
|
||||
#define VIDEO_MONITOR_EPILOGUE() { monitor_index_global = dev->prev_monitor_index; }
|
||||
|
||||
static video_timings_t timing_herculesplus = {VIDEO_ISA, 8, 16, 32, 8, 16, 32};
|
||||
|
||||
|
||||
@@ -180,7 +184,7 @@ herculesplus_in(uint16_t port, void *priv)
|
||||
break;
|
||||
|
||||
case 0x3ba:
|
||||
/* 0x50: InColor card identity */
|
||||
/* 0x10: Hercules Plus card identity */
|
||||
ret = (dev->stat & 0xf) | ((dev->stat & 8) << 4) | 0x10;
|
||||
break;
|
||||
}
|
||||
@@ -489,6 +493,7 @@ herculesplus_poll(void *priv)
|
||||
uint16_t ca = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff;
|
||||
int x, oldvc, oldsc;
|
||||
|
||||
VIDEO_MONITOR_PROLOGUE();
|
||||
if (! dev->linepos) {
|
||||
timer_advance_u64(&dev->timer, dev->dispofftime);
|
||||
dev->stat |= 1;
|
||||
@@ -602,6 +607,8 @@ herculesplus_poll(void *priv)
|
||||
if ((dev->sc == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[10] & 31) >> 1))))
|
||||
dev->con = 1;
|
||||
}
|
||||
|
||||
VIDEO_MONITOR_EPILOGUE();
|
||||
}
|
||||
|
||||
|
||||
@@ -615,10 +622,11 @@ herculesplus_init(const device_t *info)
|
||||
memset(dev, 0, sizeof(herculesplus_t));
|
||||
|
||||
dev->vram = (uint8_t *)malloc(0x10000); /* 64k VRAM */
|
||||
dev->monitor_index = monitor_index_global;
|
||||
|
||||
timer_add(&dev->timer, herculesplus_poll, dev, 1);
|
||||
|
||||
mem_mapping_add(&dev->mapping, 0xb0000, 0x10000,
|
||||
mem_mapping_add(&dev->mapping, 0xb0000, 0x08000,
|
||||
herculesplus_read,NULL,NULL,
|
||||
herculesplus_write,NULL,NULL,
|
||||
dev->vram, MEM_MAPPING_EXTERNAL, dev);
|
||||
|
||||
@@ -110,13 +110,13 @@ video_cards[] = {
|
||||
{ &cpqega_device },
|
||||
{ &ega_device },
|
||||
{ &g2_gc205_device },
|
||||
{ &hercules_device },
|
||||
{ &herculesplus_device },
|
||||
{ &hercules_device, VIDEO_FLAG_TYPE_MDA },
|
||||
{ &herculesplus_device, VIDEO_FLAG_TYPE_MDA },
|
||||
{ &incolor_device },
|
||||
{ &im1024_device },
|
||||
{ &iskra_ega_device },
|
||||
{ &et4000_kasan_isa_device },
|
||||
{ &mda_device },
|
||||
{ &mda_device, VIDEO_FLAG_TYPE_MDA },
|
||||
{ &genius_device },
|
||||
{ &nga_device },
|
||||
{ &ogc_device },
|
||||
@@ -299,7 +299,7 @@ video_prepare(void)
|
||||
|
||||
for (int i = 0; i < MONITORS_NUM; i++) {
|
||||
/* Reset the CGA palette. */
|
||||
monitors[i].mon_cga_palette = 0;
|
||||
if (monitors[i].mon_cga_palette) *monitors[i].mon_cga_palette = 0;
|
||||
cgapal_rebuild_monitor(i);
|
||||
|
||||
/* Do an inform on the default values, so that that there's some sane values initialized
|
||||
@@ -340,14 +340,17 @@ video_reset(int card)
|
||||
|
||||
/* Initialize the video card. */
|
||||
device_add(video_cards[card].device);
|
||||
}
|
||||
|
||||
if (herc_enabled) {
|
||||
if (!(card == VID_NONE)
|
||||
&& !machine_has_flags(machine, MACHINE_VIDEO_ONLY)
|
||||
&& gfxcard_2 != 0
|
||||
&& (video_cards[gfxcard_2].flags != video_cards[gfxcard].flags)) {
|
||||
video_monitor_init(1);
|
||||
monitor_index_global = 1;
|
||||
device_add(&hercules_device);
|
||||
monitor_index_global = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable the Voodoo if configured. */
|
||||
if (voodoo_enabled)
|
||||
@@ -366,6 +369,11 @@ video_card_available(int card)
|
||||
return(1);
|
||||
}
|
||||
|
||||
int
|
||||
video_card_get_flags(int card)
|
||||
{
|
||||
return video_cards[card].flags;
|
||||
}
|
||||
|
||||
const device_t *
|
||||
video_card_getdevice(int card)
|
||||
|
||||
@@ -105,7 +105,6 @@ monitor_t monitors[MONITORS_NUM];
|
||||
monitor_settings_t monitor_settings[MONITORS_NUM];
|
||||
atomic_bool doresize_monitors[MONITORS_NUM];
|
||||
int monitor_index_global = 0;
|
||||
int herc_enabled = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
void * __cdecl (*video_copy)(void *_Dst, const void *_Src, size_t _Size) = memcpy;
|
||||
@@ -621,11 +620,16 @@ cgapal_rebuild_monitor(int monitor_index)
|
||||
{
|
||||
int c;
|
||||
uint32_t* palette_lookup = monitors[monitor_index].mon_pal_lookup;
|
||||
int cga_palette_monitor = *monitors[monitor_index].mon_cga_palette;
|
||||
int cga_palette_monitor = 0;
|
||||
|
||||
/* We cannot do this (yet) if we have not been enabled yet. */
|
||||
if (video_6to8 == NULL) return;
|
||||
|
||||
if (monitors[monitor_index].target_buffer == NULL ||
|
||||
monitors[monitor_index].mon_cga_palette == NULL) return;
|
||||
|
||||
cga_palette_monitor = *monitors[monitor_index].mon_cga_palette;
|
||||
|
||||
for (c=0; c<256; c++) {
|
||||
palette_lookup[c] = makecol(video_6to8[cgapal[c].r],
|
||||
video_6to8[cgapal[c].g],
|
||||
@@ -737,14 +741,14 @@ video_update_timing(void)
|
||||
*vid_timing_write_b = ISA_CYCLES(monitor_vid_timings->write_b);
|
||||
*vid_timing_write_w = ISA_CYCLES(monitor_vid_timings->write_w);
|
||||
*vid_timing_write_l = ISA_CYCLES(monitor_vid_timings->write_l);
|
||||
} else if (vid_timings->type == VIDEO_PCI) {
|
||||
} else if (monitor_vid_timings->type == VIDEO_PCI) {
|
||||
*vid_timing_read_b = (int)(pci_timing * monitor_vid_timings->read_b);
|
||||
*vid_timing_read_w = (int)(pci_timing * monitor_vid_timings->read_w);
|
||||
*vid_timing_read_l = (int)(pci_timing * monitor_vid_timings->read_l);
|
||||
*vid_timing_write_b = (int)(pci_timing * monitor_vid_timings->write_b);
|
||||
*vid_timing_write_w = (int)(pci_timing * monitor_vid_timings->write_w);
|
||||
*vid_timing_write_l = (int)(pci_timing * monitor_vid_timings->write_l);
|
||||
} else if (vid_timings->type == VIDEO_AGP) {
|
||||
} else if (monitor_vid_timings->type == VIDEO_AGP) {
|
||||
*vid_timing_read_b = (int)(agp_timing * monitor_vid_timings->read_b);
|
||||
*vid_timing_read_w = (int)(agp_timing * monitor_vid_timings->read_w);
|
||||
*vid_timing_read_l = (int)(agp_timing * monitor_vid_timings->read_l);
|
||||
|
||||
Reference in New Issue
Block a user