-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathksystemtray2.txt
194 lines (174 loc) · 7.38 KB
/
ksystemtray2.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/**
* Please see http://basket.kde.org/systemtray-on-close-info.php
* for more informations, learn what it is and how to intagrate
* it to your application.
*/
/** ksystemtray2.h ***************************************************/
#include <ksystemtray.h>
class QWidget;
class QString;
/** Convenient class to develop the displayCloseMessage() dialog
* hopefuly integrated in KDE 3.4
* @author Sébastien Laoût
*/
class KSystemTray2 : public KSystemTray
{
Q_OBJECT
public:
KSystemTray2(QWidget *parent = 0, const char *name = 0);
~KSystemTray2();
/**
* Call this method when the user clicked the close button of the window
* (the [x]) to inform him that the application sit in the system tray
* and willn't be closed (as he is used to).
*
* You usualy call it from reimplemented KMainWindow::queryClose()
*
* @ since 3.4
*/
void displayCloseMessage(QString fileMenu = "");
};
/** ksystemtray2.cpp *************************************************/
// General:
#include <qwidget.h>
#include <qstring.h>
// To draw the systray screenshot image:
#include <qdesktopwidget.h>
#include <qmime.h>
#include <qpainter.h>
#include <qpoint.h>
#include <qpixmap.h>
// To know the program name:
#include <kglobal.h>
#include <kinstance.h>
#include <kaboutdata.h>
// Others:
#include <kmessagebox.h>
#include <kmanagerselection.h>
KSystemTray2::KSystemTray2(QWidget *parent, const char *name)
: KSystemTray(parent, name)
{
}
KSystemTray2::~KSystemTray2()
{
}
void KSystemTray2::displayCloseMessage(QString fileMenu)
{
/* IDEAS OF IMPROVEMENTS:
* - Use queuedMessageBox() but it need a dontAskAgainName parameter
* and image in QMimeSourceFactory shouldn't be removed.
* - Sometimes the systray icon is covered (a passive popup...)
* Use XComposite extension, if available, to get the kicker pixmap.
* - Perhapse desaturate the area around the proper SysTray icon,
* helping bring it into sharper focus. Or draw the cicle with XOR
* brush.
* - Perhapse add the icon in the text (eg. "... in the
* system tray ([icon])."). Add some clutter to the dialog.
*/
#if KDE_IS_VERSION( 3, 1, 90 )
// Don't do all the computations if they are unneeded:
if ( ! KMessageBox::shouldBeShownContinue("hideOnCloseInfo") )
return;
#endif
// "Default parameter". Here, to avoid a i18n() call and dependancy in the .h
if (fileMenu.isEmpty())
fileMenu = i18n("File");
// Some values we need:
QPoint g = mapToGlobal(pos());
int desktopWidth = kapp->desktop()->width();
int desktopHeight = kapp->desktop()->height();
int tw = width();
int th = height();
// We are triying to make a live screenshot of the systray icon to circle it
// and show it to the user. If no systray is used or if the icon is not visible,
// we should not show that screenshot but only a text!
// 1. Determine if the user use a system tray area or not:
QCString screenstr;
screenstr.setNum(qt_xscreen());
QCString trayatom = "_NET_SYSTEM_TRAY_S" + screenstr;
bool useSystray = (KSelectionWatcher(trayatom).owner() != None);
// 2. And then if the icon is visible too (eg. this->show() has been called):
useSystray = useSystray && isVisible();
// 3. Kicker (or another systray manager) can be visible but masked out of
// the screen (ie. on right or on left of it). We check if the icon isn't
// out of screen.
if (useSystray) {
QRect deskRect(0, 0, desktopWidth, desktopHeight);
if ( !deskRect.contains(g.x(), g.y()) ||
!deskRect.contains(g.x() + tw, g.y() + th) )
useSystray = false;
}
// 4. We raise the window containing the systray icon (typically the kicker) to
// have the most chances it is visible during the capture:
/* if (useSystray) {
// We are testing if one of the corners is hidden, and if yes, we would enter
// a time consuming process (raise kicker and wait some time):
// if (kapp->widgetAt(g) != this ||
// kapp->widgetAt(g + QPoint(tw-1, 0)) != this ||
// kapp->widgetAt(g + QPoint(0, th-1)) != this ||
// kapp->widgetAt(g + QPoint(tw-1, th-1)) != this) {
int systrayManagerWinId = topLevelWidget()->winId();
KWin::forceActiveWindow(systrayManagerWinId);
kapp->processEvents(); // Because without it the systrayManager is raised only after the messageBox is displayed
// KWin::activateWindow(systrayManagerWinId);
// kapp->processEvents(); // Because without it the systrayManager is raised only after the messageBox is displayed
// KWin::raiseWindow(systrayManagerWinId);
// kapp->processEvents(); // Because without it the systrayManager is raised only after the messageBox is displayed
sleep(1);
// TODO: Re-verify that at least one corner is now visible
// }
}*/
// KMessageBox::information(this, QString::number(g.x()) + ":" + QString::number(g.y()) + ":" +
// QString::number((int)(kapp->widgetAt(g+QPoint(1,1)))));
QString message = i18n(
"<p>Closing the main window will keep %1 running in the system tray. "
"Use <b>Quit</b> from the <b>%2</b> menu to quit the application.</p>"
).arg(KGlobal::instance()->aboutData()->programName(), "Basket");
// We are sure the systray icon is visible: ouf!
if (useSystray) {
// Compute size and position of the pixmap to be grabbed:
int w = desktopWidth / 4;
int h = desktopHeight / 9;
int x = g.x() + tw/2 - w/2; // Center the rectange in the systray icon
int y = g.y() + th/2 - h/2;
if (x < 0) x = 0; // Move the rectangle to stay in the desktop limits
if (y < 0) y = 0;
if (x + w > desktopWidth) x = desktopWidth - w;
if (y + h > desktopHeight) y = desktopHeight - h;
// Grab the desktop and draw a circle arround the icon:
QPixmap shot = QPixmap::grabWindow(qt_xrootwin(), x, y, w, h);
QPainter painter(&shot);
const int CIRCLE_MARGINS = 6;
const int CIRCLE_WIDTH = 3;
const int SHADOW_OFFSET = 1;
const int IMAGE_BORDER = 1;
int ax = g.x() - x - CIRCLE_MARGINS - 1;
int ay = g.y() - y - CIRCLE_MARGINS - 1;
painter.setPen( QPen(KApplication::palette().active().dark(), CIRCLE_WIDTH) );
painter.drawArc(ax + SHADOW_OFFSET, ay + SHADOW_OFFSET,
tw + 2*CIRCLE_MARGINS, th + 2*CIRCLE_MARGINS, 0, 16*360);
painter.setPen( QPen(Qt::red/*KApplication::palette().active().highlight()*/, CIRCLE_WIDTH) );
painter.drawArc(ax, ay, tw + 2*CIRCLE_MARGINS, th + 2*CIRCLE_MARGINS, 0, 16*360);
#if 1
// Draw the pixmap over the screenshot in case a window hide the icon:
painter.drawPixmap(g.x() - x, g.y() - y + 1, *pixmap());
#endif
painter.end();
// Then, we add a border arround the image to make it more visible:
QPixmap finalShot(w + 2*IMAGE_BORDER, h + 2*IMAGE_BORDER);
finalShot.fill(KApplication::palette().active().foreground());
painter.begin(&finalShot);
painter.drawPixmap(IMAGE_BORDER, IMAGE_BORDER, shot);
painter.end();
// Associate source to image and show the dialog:
QMimeSourceFactory::defaultFactory()->setPixmap("systray_shot", finalShot);
KMessageBox::information(this,
message + "<p><center><img source=\"systray_shot\"></center></p>",
i18n("Docking in System Tray"), "hideOnCloseInfo");
QMimeSourceFactory::defaultFactory()->setData("systray_shot", 0L);
} else {
KMessageBox::information(this,
message,
i18n("Docking in System Tray"), "hideOnCloseInfo");
}
}