2
* psiapplication.cpp - subclass of QApplication to do some workarounds
3
* Copyright (C) 2003 Michail Pishchagin
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License
7
* as published by the Free Software Foundation; either version 2
8
* of the License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this library; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
#include "psiapplication.h"
24
#include<Carbon/Carbon.h>
32
#include <X11/Xutil.h>
33
#include <X11/Xatom.h>
34
#include <X11/SM/SMlib.h>
36
// Atoms required for monitoring the freedesktop.org notification area
37
static Atom manager_atom = 0;
38
static Atom tray_selection_atom = 0;
39
Window root_window = 0;
40
Window tray_owner = None;
42
//static Atom atom_KdeNetUserTime;
43
static Atom kde_net_wm_user_time = 0;
45
//#if QT_VERSION > 0x030201
46
//#warning "Possibly, now it's time to clean up some 'focus stealing prevention' workaround code"
49
Time qt_x_last_input_time = CurrentTime;
50
//extern Time qt_x_time;
53
#ifndef FIXX11H_KeyPress
54
#define FIXX11H_KeyPress
55
const int XKeyPress = KeyPress;
57
const int KeyPress = XKeyPress;
64
// currently this file contains some Anti-"focus steling prevention" code by
65
// Lubos Lunak (l.lunak@kde.org)
67
// This should resolve all bugs with KWin3 and old Qt, but maybe it'll be useful for
68
// other window managers?
75
void setTrayOwnerWindow(Display *dsp)
77
/* This code is basically trying to mirror what happens in
78
* eggtrayicon.c:egg_tray_icon_update_manager_window()
80
// ignore events from the old tray owner
81
if (tray_owner != None)
83
XSelectInput(dsp, tray_owner, 0);
86
// obtain the Window handle for the new tray owner
88
tray_owner = XGetSelectionOwner(dsp, tray_selection_atom);
90
// we have to be able to spot DestroyNotify messages on the tray owner
91
if (tray_owner != None)
93
XSelectInput(dsp, tray_owner, StructureNotifyMask|PropertyChangeMask);
102
//----------------------------------------------------------------------------
104
//----------------------------------------------------------------------------
106
PsiApplication::PsiApplication(int &argc, char **argv, bool GUIenabled)
107
: QApplication(argc, argv, GUIenabled)
112
PsiApplication::~PsiApplication()
116
void PsiApplication::init(bool GUIenabled)
118
Q_UNUSED(GUIenabled);
124
Atom atoms_return[max];
127
//atoms[n] = &atom_KdeNetUserTime;
128
//names[n++] = (char *) "_KDE_NET_USER_TIME";
130
atoms[n] = &kde_net_wm_user_time;
131
names[n++] = (char *) "_NET_WM_USER_TIME";
132
atoms[n] = &manager_atom;
133
names[n++] = (char *) "MANAGER";
135
Display *dsp = qt_xdisplay();
137
XInternAtoms( dsp, names, n, false, atoms_return );
139
for (int i = 0; i < n; i++ )
140
*atoms[i] = atoms_return[i];
142
// get the selection type we'll use to locate the notification tray
144
snprintf(buf, sizeof(buf), "_NET_SYSTEM_TRAY_S%d", XScreenNumberOfScreen( XDefaultScreenOfDisplay(dsp) ));
145
tray_selection_atom = XInternAtom(dsp, buf, false);
147
// make a note of the window handle for the root window
148
root_window = QApplication::desktop()->winId();
150
XWindowAttributes attr;
152
// this is actually futile, since Qt overrides it at some
153
// unknown point in the near future.
154
XGetWindowAttributes(dsp, root_window, &attr);
155
XSelectInput(dsp, root_window, attr.your_event_mask | StructureNotifyMask);
157
setTrayOwnerWindow(dsp);
162
bool PsiApplication::notify(QObject *receiver, QEvent *event)
165
if( event->type() == QEvent::Show && receiver->isWidgetType())
167
QWidget* w = static_cast< QWidget* >( receiver );
168
if( w->isTopLevel() && qt_x_last_input_time != CurrentTime ) // CurrentTime means no input event yet
169
XChangeProperty( qt_xdisplay(), w->winId(), kde_net_wm_user_time, XA_CARDINAL,
170
32, PropModeReplace, (unsigned char*)&qt_x_last_input_time, 1 );
172
if( event->type() == QEvent::Hide && receiver->isWidgetType())
174
QWidget* w = static_cast< QWidget* >( receiver );
175
if( w->isTopLevel() && w->winId() != 0 )
176
XDeleteProperty( qt_xdisplay(), w->winId(), kde_net_wm_user_time );
179
return QApplication::notify(receiver, event);
183
bool PsiApplication::x11EventFilter( XEvent *_event )
185
switch ( _event->type ) {
188
if (_event->xclient.window == root_window && _event->xclient.message_type == manager_atom)
190
// A new notification area application has
191
// announced its presence
192
setTrayOwnerWindow(_event->xclient.display);
197
if (_event->xdestroywindow.event == tray_owner)
199
// there is now no known notification area.
200
// We're still looking out for the MANAGER
201
// message sent to the root window, at which
202
// point we'll have another look to see
203
// whether a notification area is available.
212
if( _event->type == ButtonPress )
213
qt_x_last_input_time = _event->xbutton.time;
215
qt_x_last_input_time = _event->xkey.time;
216
QWidget *w = activeWindow();
218
XChangeProperty( qt_xdisplay(), w->winId(), kde_net_wm_user_time, XA_CARDINAL,
219
32, PropModeReplace, (unsigned char*)&qt_x_last_input_time, 1 );
221
gettimeofday( &tv, NULL );
222
unsigned long now = tv.tv_sec * 10 + tv.tv_usec / 100000;
223
XChangeProperty(qt_xdisplay(), w->winId(),
224
atom_KdeNetUserTime, XA_CARDINAL,
225
32, PropModeReplace, (unsigned char *)&now, 1);*/
234
// process the event normally
240
bool PsiApplication::macEventFilter( EventHandlerCallRef, EventRef inEvent )
242
UInt32 eclass = GetEventClass(inEvent);
243
int etype = GetEventKind(inEvent);
244
if(eclass == 'eppc' && etype == kEventAppleEvent) {