Small code cleanups and window border color config option added.
svn path=/trunk/kdebase/kwin/; revision=98802
This commit is contained in:
parent
1e7469d54e
commit
2ade4cc7ec
6 changed files with 228 additions and 50 deletions
|
@ -1,6 +1,8 @@
|
|||
|
||||
INCLUDES = $(all_includes)
|
||||
|
||||
SUBDIRS = . config
|
||||
|
||||
kde_module_LTLIBRARIES = libkwinquartz.la
|
||||
|
||||
libkwinquartz_la_SOURCES = quartz.cpp
|
||||
|
|
16
clients/quartz/config/Makefile.am
Normal file
16
clients/quartz/config/Makefile.am
Normal file
|
@ -0,0 +1,16 @@
|
|||
INCLUDES = $(all_includes)
|
||||
|
||||
kde_module_LTLIBRARIES = libkwinquartz_config.la
|
||||
|
||||
libkwinquartz_config_la_SOURCES = config.cpp
|
||||
libkwinquartz_config_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN)
|
||||
libkwinquartz_config_la_LIBADD = $(LIB_KDEUI)
|
||||
|
||||
METASOURCES = AUTO
|
||||
noinst_HEADERS = config.h
|
||||
|
||||
lnkdir = $(kde_datadir)/kwin/
|
||||
|
||||
###KMAKE-start (don't edit or delete this block)
|
||||
|
||||
###KMAKE-end
|
90
clients/quartz/config/config.cpp
Normal file
90
clients/quartz/config/config.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
This file contains the quartz configuration widget...
|
||||
|
||||
Copyright (c) 2001
|
||||
Karol Szwed (gallium) <karlmail@usa.net>
|
||||
http://gallium.n3.net/
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <qwhatsthis.h>
|
||||
#include <klocale.h>
|
||||
|
||||
|
||||
// KWin client config plugin interface
|
||||
extern "C"
|
||||
{
|
||||
QObject* allocate_config( KConfig* conf, QWidget* parent )
|
||||
{
|
||||
return(new QuartzConfig(conf, parent));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NOTE:
|
||||
// 'conf' is a pointer to the kwindecoration modules open kwin config,
|
||||
// and is by default set to the "Style" group.
|
||||
//
|
||||
// 'parent' is the parent of the QObject, which is a VBox inside the
|
||||
// Configure tab in kwindecoration
|
||||
|
||||
QuartzConfig::QuartzConfig( KConfig* conf, QWidget* parent )
|
||||
: QObject( parent )
|
||||
{
|
||||
gb = new QGroupBox( 1, Qt::Horizontal, i18n("Quartz Decoration Settings"), parent );
|
||||
|
||||
cbColorBorder = new QCheckBox( i18n("Draw window frames using &titlebar colors"), gb );
|
||||
QWhatsThis::add( cbColorBorder, i18n("When selected, the window decoration borders "
|
||||
"are drawn using the titlebar colors. Otherwise, they are "
|
||||
"drawn using normal border colors instead.") );
|
||||
// Load configuration options
|
||||
load( conf );
|
||||
|
||||
// Ensure we track user changes properly
|
||||
connect( cbColorBorder, SIGNAL(clicked()), this, SLOT(slotSelectionChanged()) );
|
||||
|
||||
// Make the widgets visible in kwindecoration
|
||||
gb->show();
|
||||
}
|
||||
|
||||
|
||||
QuartzConfig::~QuartzConfig()
|
||||
{
|
||||
delete cbColorBorder;
|
||||
delete gb;
|
||||
}
|
||||
|
||||
|
||||
void QuartzConfig::slotSelectionChanged()
|
||||
{
|
||||
emit changed();
|
||||
}
|
||||
|
||||
|
||||
// Loads the configurable options from the kwinrc config file
|
||||
// It is passed the open config from kwindecoration to improve efficiency
|
||||
void QuartzConfig::load( KConfig* conf )
|
||||
{
|
||||
conf->setGroup("Quartz");
|
||||
bool override = conf->readBoolEntry( "UseTitleBarBorderColors", true );
|
||||
cbColorBorder->setChecked( override );
|
||||
}
|
||||
|
||||
|
||||
// Saves the configurable options to the kwinrc config file
|
||||
void QuartzConfig::save( KConfig* conf )
|
||||
{
|
||||
conf->setGroup("Quartz");
|
||||
conf->writeEntry( "UseTitleBarBorderColors", cbColorBorder->isChecked() );
|
||||
}
|
||||
|
||||
|
||||
// Sets UI widget defaults which must correspond to style defaults
|
||||
void QuartzConfig::defaults()
|
||||
{
|
||||
cbColorBorder->setChecked( true );
|
||||
}
|
||||
|
||||
#include "config.moc"
|
||||
|
||||
// vim: ts=4
|
44
clients/quartz/config/config.h
Normal file
44
clients/quartz/config/config.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
This file contains the quartz configuration widget...
|
||||
|
||||
Copyright (c) 2001
|
||||
Karol Szwed (gallium) <karlmail@usa.net>
|
||||
http://gallium.n3.net/
|
||||
*/
|
||||
|
||||
#ifndef __KDE_QUARTZCONFIG_H
|
||||
#define __KDE_QUARTZCONFIG_H
|
||||
|
||||
#include <qcheckbox.h>
|
||||
#include <qgroupbox.h>
|
||||
#include <kconfig.h>
|
||||
|
||||
class QuartzConfig: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QuartzConfig( KConfig* conf, QWidget* parent );
|
||||
~QuartzConfig();
|
||||
|
||||
// These public signals/slots work similar to KCM modules
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
public slots:
|
||||
void load( KConfig* conf );
|
||||
void save( KConfig* conf );
|
||||
void defaults();
|
||||
|
||||
protected slots:
|
||||
void slotSelectionChanged(); // Internal use
|
||||
|
||||
private:
|
||||
QCheckBox* cbColorBorder;
|
||||
QGroupBox* gb;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
// vim: ts=4
|
|
@ -1,3 +1,4 @@
|
|||
// $Id$
|
||||
/*
|
||||
Gallium-Quartz KWin client
|
||||
|
||||
|
@ -17,7 +18,6 @@
|
|||
#include <kpixmapeffect.h>
|
||||
#include <kdrawutil.h>
|
||||
#include <qlayout.h>
|
||||
#include <qlabel.h>
|
||||
#include <qdrawutil.h>
|
||||
#include <qbitmap.h>
|
||||
#include "../../workspace.h"
|
||||
|
@ -82,6 +82,7 @@ static unsigned char pinup_dgray_bits[] = {
|
|||
|
||||
// Titlebar button positions
|
||||
bool stickyButtonOnLeft = true;
|
||||
bool coloredFrame = true;
|
||||
|
||||
KPixmap* titleBlocks = NULL;
|
||||
KPixmap* ititleBlocks = NULL;
|
||||
|
@ -90,6 +91,7 @@ KPixmap* pinUpPix = NULL;
|
|||
KPixmap* ipinDownPix = NULL;
|
||||
KPixmap* ipinUpPix = NULL;
|
||||
|
||||
bool quartz_initialized = false;
|
||||
QuartzHandler* clientHandler;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -97,23 +99,28 @@ QuartzHandler* clientHandler;
|
|||
|
||||
QuartzHandler::QuartzHandler()
|
||||
{
|
||||
quartz_initialized = false;
|
||||
readConfig();
|
||||
createPixmaps();
|
||||
quartz_initialized = true;
|
||||
connect( options, SIGNAL(resetClients()), this, SLOT(slotReset()) );
|
||||
}
|
||||
|
||||
|
||||
QuartzHandler::~QuartzHandler()
|
||||
{
|
||||
quartz_initialized = false;
|
||||
freePixmaps();
|
||||
}
|
||||
|
||||
|
||||
void QuartzHandler::slotReset()
|
||||
{
|
||||
quartz_initialized = false;
|
||||
freePixmaps();
|
||||
readConfig();
|
||||
createPixmaps();
|
||||
quartz_initialized = true;
|
||||
|
||||
// Make kwin create new clients for each window
|
||||
Workspace::self()->slotResetAllClientsDelayed();
|
||||
|
@ -122,7 +129,10 @@ void QuartzHandler::slotReset()
|
|||
|
||||
void QuartzHandler::readConfig()
|
||||
{
|
||||
// KConfig* conf = KGlobal::config();
|
||||
KConfig* conf = KGlobal::config();
|
||||
conf->setGroup("Quartz");
|
||||
coloredFrame = conf->readBoolEntry( "UseTitleBarBorderColors", true );
|
||||
|
||||
// A small hack to make the sticky button look nicer
|
||||
stickyButtonOnLeft = (bool)options->titleButtonsLeft().contains( 'S' );
|
||||
}
|
||||
|
@ -188,50 +198,49 @@ void QuartzHandler::createPixmaps()
|
|||
drawBlocks( ititleBlocks, *ititleBlocks, c, c2 );
|
||||
|
||||
// Set the sticky pin pixmaps;
|
||||
QColorGroup g;
|
||||
QPainter p;
|
||||
|
||||
g2 = options->colorGroup( stickyButtonOnLeft ? Options::TitleBar : Options::TitleBlend, true );
|
||||
if ( stickyButtonOnLeft )
|
||||
c = g2.background().light(130);
|
||||
else
|
||||
c = g2.background();
|
||||
|
||||
g = options->colorGroup( stickyButtonOnLeft ? Options::TitleBar : Options::TitleBlend, true );
|
||||
c = stickyButtonOnLeft ? g.background().light(130) : g.background();
|
||||
g2 = options->colorGroup( Options::ButtonBg, true );
|
||||
|
||||
pinUpPix = new KPixmap();
|
||||
pinUpPix->resize(16, 16);
|
||||
p.begin( pinUpPix );
|
||||
p.fillRect( 0, 0, 16, 16, c);
|
||||
kColorBitmaps( &p, g2, 0, 0, 16, 16, true, pinup_white_bits, pinup_gray_bits, NULL,
|
||||
pinup_dgray_bits, NULL, NULL );
|
||||
kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pinup_white_bits,
|
||||
pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL );
|
||||
p.end();
|
||||
|
||||
pinDownPix = new KPixmap();
|
||||
pinDownPix->resize(16, 16);
|
||||
p.begin( pinDownPix );
|
||||
p.fillRect( 0, 0, 16, 16, c);
|
||||
kColorBitmaps( &p, g2, 0, 0, 16, 16, true, pindown_white_bits, pindown_gray_bits, NULL,
|
||||
pindown_dgray_bits, NULL, NULL );
|
||||
kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pindown_white_bits,
|
||||
pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL );
|
||||
p.end();
|
||||
|
||||
|
||||
// Inactive pins
|
||||
g2 = options->colorGroup( stickyButtonOnLeft ? Options::TitleBar : Options::TitleBlend, false );
|
||||
if ( stickyButtonOnLeft )
|
||||
c = g2.background().light(130);
|
||||
else
|
||||
c = g2.background();
|
||||
g = options->colorGroup( stickyButtonOnLeft ? Options::TitleBar : Options::TitleBlend, false );
|
||||
c = stickyButtonOnLeft ? g.background().light(130) : g.background();
|
||||
g2 = options->colorGroup( Options::ButtonBg, false );
|
||||
|
||||
ipinUpPix = new KPixmap();
|
||||
ipinUpPix->resize(16, 16);
|
||||
p.begin( ipinUpPix );
|
||||
p.fillRect( 0, 0, 16, 16, c);
|
||||
kColorBitmaps( &p, g2, 0, 0, 16, 16, true, pinup_white_bits, pinup_gray_bits, NULL,
|
||||
pinup_dgray_bits, NULL, NULL );
|
||||
kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pinup_white_bits,
|
||||
pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL );
|
||||
p.end();
|
||||
|
||||
ipinDownPix = new KPixmap();
|
||||
ipinDownPix->resize(16, 16);
|
||||
p.begin( ipinDownPix );
|
||||
p.fillRect( 0, 0, 16, 16, c);
|
||||
kColorBitmaps( &p, g2, 0, 0, 16, 16, true, pindown_white_bits, pindown_gray_bits, NULL,
|
||||
pindown_dgray_bits, NULL, NULL );
|
||||
kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pindown_white_bits,
|
||||
pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL );
|
||||
p.end();
|
||||
}
|
||||
|
||||
|
@ -311,6 +320,10 @@ void QuartzButton::setBitmap(const unsigned char *bitmap)
|
|||
|
||||
void QuartzButton::drawButton(QPainter *p)
|
||||
{
|
||||
// Never paint if the pixmaps have not been created
|
||||
if (!quartz_initialized)
|
||||
return;
|
||||
|
||||
QColor c;
|
||||
|
||||
if (isLeft)
|
||||
|
@ -343,17 +356,10 @@ void QuartzButton::drawButton(QPainter *p)
|
|||
|
||||
// Select the right sticky button to paint
|
||||
if (client->isActive())
|
||||
{
|
||||
if (isOn())
|
||||
btnpix = *pinDownPix;
|
||||
else
|
||||
btnpix = *pinUpPix;
|
||||
} else {
|
||||
if (isOn())
|
||||
btnpix = *ipinDownPix;
|
||||
else
|
||||
btnpix = *ipinUpPix;
|
||||
}
|
||||
btnpix = isOn() ? *pinDownPix : *pinUpPix;
|
||||
else
|
||||
btnpix = isOn() ? *ipinDownPix : *ipinUpPix;
|
||||
|
||||
} else
|
||||
btnpix = client->miniIcon();
|
||||
|
||||
|
@ -424,7 +430,10 @@ QuartzClient::QuartzClient( Workspace *ws, WId w, QWidget *parent,
|
|||
QGridLayout* g = new QGridLayout(this, 0, 0, 0);
|
||||
g->setResizeMode(QLayout::FreeResize);
|
||||
g->addRowSpacing(0, 3); // Top grab bar
|
||||
g->addWidget(windowWrapper(), 3, 1);
|
||||
g->addWidget(windowWrapper(), 3, 1);
|
||||
// without the next line, unshade flickers
|
||||
g->addItem( new QSpacerItem( 0, 0, QSizePolicy::Fixed,
|
||||
QSizePolicy::Expanding ) );
|
||||
g->setRowStretch(3, 10); // Wrapped window
|
||||
g->addRowSpacing(2, 1); // line under titlebar
|
||||
g->addRowSpacing(4, 4); // bottom handles
|
||||
|
@ -459,7 +468,8 @@ void QuartzClient::addClientButtons( const QString& s, bool isLeft )
|
|||
case 'M':
|
||||
if (!button[BtnMenu])
|
||||
{
|
||||
button[BtnMenu] = new QuartzButton(this, "menu", largeButtons, isLeft, false, NULL);
|
||||
button[BtnMenu] = new QuartzButton(this, "menu",
|
||||
largeButtons, isLeft, false, NULL);
|
||||
connect( button[BtnMenu], SIGNAL(pressed()), this, SLOT(menuButtonPressed()) );
|
||||
hb->addWidget( button[BtnMenu] );
|
||||
}
|
||||
|
@ -469,7 +479,8 @@ void QuartzClient::addClientButtons( const QString& s, bool isLeft )
|
|||
case 'S':
|
||||
if (!button[BtnSticky])
|
||||
{
|
||||
button[BtnSticky] = new QuartzButton(this, "menu", largeButtons, isLeft, true, NULL);
|
||||
button[BtnSticky] = new QuartzButton(this, "menu",
|
||||
largeButtons, isLeft, true, NULL);
|
||||
button[BtnSticky]->turnOn( isSticky() );
|
||||
connect( button[BtnSticky], SIGNAL(clicked()), this, SLOT(toggleSticky()) );
|
||||
hb->addSpacing(1);
|
||||
|
@ -482,8 +493,9 @@ void QuartzClient::addClientButtons( const QString& s, bool isLeft )
|
|||
case 'H':
|
||||
if( providesContextHelp() && (!button[BtnHelp]) )
|
||||
{
|
||||
button[BtnHelp] = new QuartzButton(this, "help", largeButtons, isLeft, true, question_bits);
|
||||
connect( button[BtnHelp], SIGNAL( clicked() ), this, SLOT( contextHelp() ));
|
||||
button[BtnHelp] = new QuartzButton(this, "help",
|
||||
largeButtons, isLeft, true, question_bits);
|
||||
connect( button[BtnHelp], SIGNAL( clicked() ), this, SLOT(contextHelp()));
|
||||
hb->addWidget( button[BtnHelp] );
|
||||
}
|
||||
break;
|
||||
|
@ -492,7 +504,8 @@ void QuartzClient::addClientButtons( const QString& s, bool isLeft )
|
|||
case 'I':
|
||||
if ( (!button[BtnIconify]) && isMinimizable())
|
||||
{
|
||||
button[BtnIconify] = new QuartzButton(this, "iconify", largeButtons, isLeft, true, iconify_bits);
|
||||
button[BtnIconify] = new QuartzButton(this, "iconify",
|
||||
largeButtons, isLeft, true, iconify_bits);
|
||||
connect( button[BtnIconify], SIGNAL( clicked()), this, SLOT(iconify()) );
|
||||
hb->addWidget( button[BtnIconify] );
|
||||
}
|
||||
|
@ -502,7 +515,8 @@ void QuartzClient::addClientButtons( const QString& s, bool isLeft )
|
|||
case 'A':
|
||||
if ( (!button[BtnMax]) && isMaximizable())
|
||||
{
|
||||
button[BtnMax] = new QuartzButton(this, "maximize", largeButtons, isLeft, true, maximize_bits);
|
||||
button[BtnMax] = new QuartzButton(this, "maximize",
|
||||
largeButtons, isLeft, true, maximize_bits);
|
||||
connect( button[BtnMax], SIGNAL( clicked()), this, SLOT(slotMaximize()) );
|
||||
hb->addWidget( button[BtnMax] );
|
||||
}
|
||||
|
@ -512,7 +526,8 @@ void QuartzClient::addClientButtons( const QString& s, bool isLeft )
|
|||
case 'X':
|
||||
if (!button[BtnClose])
|
||||
{
|
||||
button[BtnClose] = new QuartzButton(this, "close", largeButtons, isLeft, true, close_bits);
|
||||
button[BtnClose] = new QuartzButton(this, "close",
|
||||
largeButtons, isLeft, true, close_bits);
|
||||
connect( button[BtnClose], SIGNAL( clicked()), this, SLOT(closeWindow()) );
|
||||
hb->addWidget( button[BtnClose] );
|
||||
}
|
||||
|
@ -581,6 +596,11 @@ void QuartzClient::captionChange( const QString& )
|
|||
// Quartz Paint magic goes here.
|
||||
void QuartzClient::paintEvent( QPaintEvent* )
|
||||
{
|
||||
// Never paint if the pixmaps have not been created
|
||||
if (!quartz_initialized)
|
||||
return;
|
||||
|
||||
QColorGroup g;
|
||||
QPainter p(this);
|
||||
|
||||
// Obtain widget bounds.
|
||||
|
@ -593,7 +613,11 @@ void QuartzClient::paintEvent( QPaintEvent* )
|
|||
int h = r.height();
|
||||
|
||||
// Draw part of the frame that is the title color
|
||||
QColorGroup g = options->colorGroup(Options::TitleBar, isActive());
|
||||
|
||||
if( coloredFrame )
|
||||
g = options->colorGroup(Options::TitleBar, isActive());
|
||||
else
|
||||
g = options->colorGroup(Options::Frame, isActive());
|
||||
|
||||
// Draw outer highlights and lowlights
|
||||
p.setPen( g.light().light(120) );
|
||||
|
@ -604,7 +628,10 @@ void QuartzClient::paintEvent( QPaintEvent* )
|
|||
p.drawLine( x, y2, x2, y2 );
|
||||
|
||||
// Fill out the border edges
|
||||
p.setPen( g.background().light(130) );
|
||||
if ( coloredFrame)
|
||||
p.setPen( g.background().light(130) );
|
||||
else
|
||||
p.setPen( g.background() );
|
||||
p.drawRect( x+1, y+1, w-2, h-2 );
|
||||
p.drawRect( x+2, y+2, w-4, h-4 );
|
||||
|
||||
|
@ -649,13 +676,13 @@ void QuartzClient::paintEvent( QPaintEvent* )
|
|||
QFont fnt = options->font(true);
|
||||
if ( !largeButtons )
|
||||
{
|
||||
fnt.setPointSize( fnt.pointSize() - 2 ); // Shrink font by 2pt
|
||||
fnt.setPointSize( fnt.pointSize() - 3 ); // Shrink font by 3pt
|
||||
fnt.setWeight( QFont::Normal ); // and disable bold
|
||||
}
|
||||
p2.setFont( fnt );
|
||||
|
||||
p2.setPen( options->color(Options::Font, isActive() ));
|
||||
p2.drawText(r.x(), 0, r.width()-3, r.height()-1,
|
||||
p2.drawText(r.x(), 0, r.width()-3, r.height(),
|
||||
AlignLeft | AlignVCenter, caption() );
|
||||
p2.end();
|
||||
|
||||
|
@ -786,3 +813,4 @@ extern "C"
|
|||
|
||||
|
||||
#include "quartz.moc"
|
||||
// vim: ts=4
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// $Id$
|
||||
/*
|
||||
Gallium-Quartz KWin client
|
||||
|
||||
|
@ -20,11 +21,8 @@
|
|||
#include <kpixmap.h>
|
||||
#include "../../client.h"
|
||||
|
||||
class QLabel;
|
||||
class QSpacerItem;
|
||||
class QHBoxLayout;
|
||||
class QGridLayout;
|
||||
|
||||
|
||||
namespace KWinInternal {
|
||||
|
||||
|
@ -41,7 +39,6 @@ class QuartzHandler: public QObject
|
|||
|
||||
private:
|
||||
void readConfig();
|
||||
void initTheme();
|
||||
void createPixmaps();
|
||||
void freePixmaps();
|
||||
void drawBlocks(KPixmap* pi, KPixmap &p, const QColor &c1, const QColor &c2);
|
||||
|
@ -62,7 +59,7 @@ class QuartzButton : public QButton
|
|||
protected:
|
||||
void mousePressEvent( QMouseEvent* e );
|
||||
void mouseReleaseEvent( QMouseEvent* e );
|
||||
virtual void drawButton(QPainter *p);
|
||||
void drawButton(QPainter *p);
|
||||
void drawButtonLabel(QPainter*) {;}
|
||||
|
||||
Client* client;
|
||||
|
@ -78,7 +75,6 @@ class QuartzClient : public KWinInternal::Client
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Buttons{ BtnHelp=0, BtnMax, BtnIconify, BtnClose, BtnMenu, BtnSticky, BtnCount };
|
||||
QuartzClient( Workspace *ws, WId w, QWidget *parent=0, const char *name=0 );
|
||||
~QuartzClient() {;}
|
||||
|
||||
|
@ -100,6 +96,7 @@ class QuartzClient : public KWinInternal::Client
|
|||
void calcHiddenButtons();
|
||||
void addClientButtons( const QString& s, bool isLeft=true );
|
||||
|
||||
enum Buttons{ BtnHelp=0, BtnMax, BtnIconify, BtnClose, BtnMenu, BtnSticky, BtnCount };
|
||||
QuartzButton* button[ QuartzClient::BtnCount ];
|
||||
int lastButtonWidth;
|
||||
int titleHeight;
|
||||
|
@ -111,3 +108,4 @@ class QuartzClient : public KWinInternal::Client
|
|||
};
|
||||
|
||||
#endif
|
||||
// vim: ts=4
|
||||
|
|
Loading…
Reference in a new issue