00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "kwindowsystem.h"
00023 #include "kwindowinfo_mac_p.h"
00024
00025 #include <kiconloader.h>
00026 #include <klocale.h>
00027 #include <kuniqueapplication.h>
00028 #include <kxerrorhandler.h>
00029 #include <QtGui/QBitmap>
00030 #include <QDesktopWidget>
00031 #include <QtGui/QDialog>
00032 #include <QtDBus/QtDBus>
00033 #include <kdebug.h>
00034
00035 #include <Carbon/Carbon.h>
00036
00037
00038
00039
00040
00041
00042
00043 static bool operator<(const ProcessSerialNumber& a, const ProcessSerialNumber& b)
00044 {
00045 if (a.lowLongOfPSN != b.lowLongOfPSN) return a.lowLongOfPSN < b.lowLongOfPSN;
00046 return a.highLongOfPSN < b.highLongOfPSN;
00047 }
00048
00049 class KWindowSystemPrivate : QObject
00050 {
00051 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00052 Q_OBJECT
00053 #endif
00054 public:
00055 KWindowSystemPrivate();
00056
00057 QMap<WId, KWindowInfo> windows;
00058 QList<WId> winids;
00059 QMap<pid_t, AXObserverRef> newWindowObservers;
00060 QMap<pid_t, AXObserverRef> windowClosedObservers;
00061 QMap<ProcessSerialNumber, WId> processes;
00062 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00063 QList<KWindowInfo> nonProcessedWindows;
00064 #endif
00065
00066 EventTargetRef m_eventTarget;
00067 EventHandlerUPP m_eventHandler;
00068 EventTypeSpec m_eventType[2];
00069 EventHandlerRef m_curHandler;
00070
00071 void applicationLaunched(const ProcessSerialNumber& psn);
00072 void applicationTerminated(const ProcessSerialNumber& psn);
00073
00074 bool m_noEmit;
00075 bool waitingForTimer;
00076
00077 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00078 void newWindow(AXUIElementRef element, void* windowInfoPrivate);
00079 void windowClosed(AXUIElementRef element, void* windowInfoPrivate);
00080 #endif
00081
00082 static KWindowSystemPrivate* self() { return KWindowSystem::s_d_func(); }
00083 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00084 public slots:
00085 void tryRegisterProcess();
00086 #endif
00087 };
00088
00089 class KWindowSystemStaticContainer {
00090 public:
00091 KWindowSystemStaticContainer() : d (new KWindowSystemPrivate) { }
00092 KWindowSystem kwm;
00093 KWindowSystemPrivate* d;
00094 };
00095
00096 K_GLOBAL_STATIC(KWindowSystemStaticContainer, g_kwmInstanceContainer)
00097
00098 static OSStatus applicationEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void * inUserData)
00099 {
00100 KWindowSystemPrivate* d = (KWindowSystemPrivate*) inUserData;
00101
00102 UInt32 kind;
00103
00104 kind = GetEventKind(inEvent);
00105 ProcessSerialNumber psn;
00106 if (GetEventParameter(inEvent, kEventParamProcessID, typeProcessSerialNumber, NULL, sizeof psn, NULL, &psn) != noErr) {
00107 kWarning() << "Error getting event parameter in application event";
00108 return eventNotHandledErr;
00109 }
00110
00111 if (kind == kEventAppLaunched) {
00112 d->applicationLaunched(psn);
00113 } else if (kind == kEventAppTerminated) {
00114 d->applicationTerminated(psn);
00115 }
00116
00117 return noErr;
00118 }
00119
00120 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00121 static void windowClosedObserver(AXObserverRef observer, AXUIElementRef element, CFStringRef notification, void* refcon)
00122 {
00123 KWindowSystemPrivate::self()->windowClosed(element, refcon);
00124 }
00125
00126 static void newWindowObserver(AXObserverRef observer, AXUIElementRef element, CFStringRef notification, void* refcon)
00127 {
00128 KWindowSystemPrivate::self()->newWindow(element, refcon);
00129 }
00130 #endif
00131
00132 KWindowSystemPrivate::KWindowSystemPrivate()
00133 : QObject(0), m_noEmit(true), waitingForTimer(false)
00134 {
00135
00136 ProcessSerialNumber psn = {0, kNoProcess};
00137 while (GetNextProcess(&psn) == noErr) {
00138 kDebug(240) << "calling appLaunched for " << psn.lowLongOfPSN << ":" << psn.highLongOfPSN;
00139 applicationLaunched(psn);
00140 }
00141
00142 m_noEmit = false;
00143
00144
00145 m_eventTarget = GetApplicationEventTarget();
00146 m_eventHandler = NewEventHandlerUPP(applicationEventHandler);
00147 m_eventType[0].eventClass = kEventClassApplication;
00148 m_eventType[0].eventKind = kEventAppLaunched;
00149 m_eventType[1].eventClass = kEventClassApplication;
00150 m_eventType[1].eventKind = kEventAppTerminated;
00151 if (InstallEventHandler(m_eventTarget, m_eventHandler, 2, m_eventType, this, &m_curHandler) != noErr) {
00152 kDebug(240) << "Installing event handler failed!\n";
00153 }
00154 }
00155
00156 void KWindowSystemPrivate::applicationLaunched(const ProcessSerialNumber& psn) {
00157 kDebug(240) << "new app: " << psn.lowLongOfPSN << ":" << psn.highLongOfPSN;
00158 ProcessInfoRec pinfo;
00159 FSSpec appSpec;
00160 pinfo.processInfoLength = sizeof pinfo;
00161 pinfo.processName = 0;
00162 pinfo.processAppSpec = &appSpec;
00163 GetProcessInformation(&psn, &pinfo);
00164 if ((pinfo.processMode & modeOnlyBackground) != 0) return;
00165
00166
00167 KWindowInfo winfo(0, 0);
00168 windows[winfo.win()] = winfo;
00169 winids.append(winfo.win());
00170 winfo.d->setProcessSerialNumber(psn);
00171 pid_t pid = winfo.d->pid();
00172 processes[psn] = winfo.win();
00173 kDebug(240) << " pid:" << pid;
00174 AXUIElementRef app = AXUIElementCreateApplication(pid);
00175 winfo.d->setAxElement(app);
00176 if (!m_noEmit) emit KWindowSystem::self()->windowAdded(winfo.win());
00177
00178 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00179
00180 AXObserverRef observer, newObserver;
00181 OSStatus err;
00182 if (AXObserverCreate(pid, windowClosedObserver, &observer) == noErr) {
00183 CFRunLoopAddSource(CFRunLoopGetCurrent(), AXObserverGetRunLoopSource(observer), kCFRunLoopCommonModes);
00184 windowClosedObservers[pid] = observer;
00185 }
00186 if ((err = AXObserverCreate(pid, newWindowObserver, &newObserver)) == noErr) {
00187 CFRunLoopAddSource(CFRunLoopGetCurrent(), AXObserverGetRunLoopSource(newObserver), kCFRunLoopCommonModes);
00188 newWindowObservers[pid] = newObserver;
00189 if ((err = AXObserverAddNotification(newObserver, app, kAXWindowCreatedNotification, winfo.d)) != noErr) {
00190 kDebug(240) << "Error " << err << " adding notification to observer";
00191
00192
00193 QTimer::singleShot(500, this, SLOT(tryRegisterProcess()));
00194 nonProcessedWindows.append(winfo);
00195 return;
00196 } else
00197 kDebug(240) << "Added notification and observer";
00198 } else {
00199 kDebug(240) << "Error creating observer";
00200 }
00201
00202
00203 CFIndex windowsInApp;
00204 AXUIElementGetAttributeValueCount(app, kAXWindowsAttribute, &windowsInApp);
00205 CFArrayRef array;
00206 AXUIElementCopyAttributeValue(app, kAXWindowsAttribute, (CFTypeRef*)&array);
00207 for (CFIndex j = 0; j < windowsInApp; j++) {
00208 AXUIElementRef win = (AXUIElementRef) CFArrayGetValueAtIndex(array, j);
00209 newWindow(win, winfo.d);
00210 }
00211 #endif
00212 }
00213
00214 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00215 void KWindowSystemPrivate::tryRegisterProcess()
00216 {
00217 kDebug(240) << "Single-shot timer, trying to register processes";
00218 while (!nonProcessedWindows.empty()) {
00219 KWindowInfo winfo = nonProcessedWindows.takeLast();
00220 pid_t pid = winfo.d->pid();
00221 AXUIElementRef app = winfo.d->axElement();
00222 ProcessSerialNumber psn = winfo.d->psn();
00223
00224
00225 AXObserverRef observer;
00226 OSStatus err;
00227 observer = newWindowObservers[pid];
00228 if ((err = AXObserverAddNotification(observer, app, kAXWindowCreatedNotification, winfo.d)) != noErr) {
00229 kDebug(240) << "Error " << err << " adding notification to observer";
00230 } else
00231 kDebug(240) << "Added notification and observer";
00232
00233 observer = windowClosedObservers[pid];
00234
00235 CFIndex windowsInApp;
00236 AXUIElementGetAttributeValueCount(app, kAXWindowsAttribute, &windowsInApp);
00237 CFArrayRef array;
00238 AXUIElementCopyAttributeValue(app, kAXWindowsAttribute, (CFTypeRef*)&array);
00239 for (CFIndex j = 0; j < windowsInApp; j++) {
00240 AXUIElementRef win = (AXUIElementRef) CFArrayGetValueAtIndex(array, j);
00241 newWindow(win, winfo.d);
00242 }
00243 }
00244 }
00245 #endif
00246
00247 void KWindowSystemPrivate::applicationTerminated(const ProcessSerialNumber& psn)
00248 {
00249 kDebug(240) << "Terminated PSN: " << psn.lowLongOfPSN << ":" << psn.highLongOfPSN;
00250 WId id = processes[psn];
00251 if (windows.contains(id)) {
00252 KWindowInfo winfo = windows[id];
00253 foreach (KWindowInfo::Private* wi, winfo.d->children) {
00254 winids.removeAll(wi->win);
00255 emit KWindowSystem::self()->windowRemoved(wi->win);
00256 }
00257 winids.removeAll(id);
00258 emit KWindowSystem::self()->windowRemoved(winfo.win());
00259 }
00260 }
00261
00262 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00263 void KWindowSystemPrivate::windowClosed(AXUIElementRef element, void* refcon)
00264 {
00265 kDebug(240) << "Received window closed notification";
00266
00267 KWindowInfo::Private* wind = (KWindowInfo::Private*) refcon;
00268 KWindowInfo::Private* parent = wind->parent;
00269 parent->children.removeAll(wind);
00270 winids.removeAll(wind->win);
00271 if (!m_noEmit) emit KWindowSystem::self()->windowRemoved(wind->win);
00272 }
00273
00274 void KWindowSystemPrivate::newWindow(AXUIElementRef win, void* refcon)
00275 {
00276 kDebug(240) << "Received new window notification";
00277
00278 KWindowInfo::Private* winfod = (KWindowInfo::Private*) refcon;
00279 pid_t pid = winfod->pid();
00280 ProcessSerialNumber psn = winfod->psn();
00281 AXObserverRef observer = windowClosedObservers[pid];
00282
00283 KWindowInfo win2(0, 0);
00284
00285 if (AXObserverAddNotification(observer, win, kAXUIElementDestroyedNotification, win2.d) != noErr) {
00286
00287 kDebug(240) "error adding closed observer to window.";
00288 return;
00289 }
00290
00291 windows[win2.win()] = win2;
00292 winids.append(win2.win());
00293 win2.d->setProcessSerialNumber(psn);
00294 win2.d->setAxElement(win);
00295 winfod->children.append(win2.d);
00296 win2.d->parent = winfod;
00297 if (!m_noEmit) emit KWindowSystem::self()->windowAdded(win2.win());
00298 }
00299 #endif
00300
00301 KWindowSystem* KWindowSystem::self()
00302 {
00303 return &(g_kwmInstanceContainer->kwm);
00304 }
00305
00306 KWindowSystemPrivate* KWindowSystem::s_d_func()
00307 {
00308 return g_kwmInstanceContainer->d;
00309 }
00310
00311 const QList<WId>& KWindowSystem::windows()
00312 {
00313 KWindowSystemPrivate *d = KWindowSystem::s_d_func();
00314 return d->winids;
00315 }
00316
00317 bool KWindowSystem::hasWId(WId id)
00318 {
00319 KWindowSystemPrivate *d = KWindowSystem::s_d_func();
00320 return d->windows.contains(id);
00321 }
00322
00323 KWindowInfo KWindowSystem::windowInfo( WId win, unsigned long properties, unsigned long properties2 )
00324 {
00325 KWindowSystemPrivate *d = KWindowSystem::s_d_func();
00326 if (d->windows.contains(win)) {
00327 return d->windows[win];
00328 } else {
00329 return KWindowInfo( win, properties, properties2 );
00330 }
00331 }
00332
00333 QList<WId> KWindowSystem::stackingOrder()
00334 {
00335
00336 QList<WId> lst;
00337 kDebug(240) << "QList<WId> KWindowSystem::stackingOrder() isn't yet implemented!";
00338 return lst;
00339 }
00340
00341 WId KWindowSystem::activeWindow()
00342 {
00343
00344 kDebug(240) << "WId KWindowSystem::activeWindow() isn't yet implemented!";
00345 return 0;
00346 }
00347
00348 void KWindowSystem::activateWindow( WId win, long time )
00349 {
00350
00351 kDebug(240) << "KWindowSystem::activateWindow( WId win, long time )isn't yet implemented!";
00352 KWindowSystemPrivate *d = KWindowSystem::s_d_func();
00353 if (d->windows.contains(win)) {
00354 ProcessSerialNumber psn = d->windows[win].d->psn();
00355 SetFrontProcess(&psn);
00356 }
00357 }
00358
00359 void KWindowSystem::forceActiveWindow( WId win, long time )
00360 {
00361
00362 kDebug(240) << "KWindowSystem::forceActiveWindow( WId win, long time ) isn't yet implemented!";
00363 activateWindow(win, time);
00364 }
00365
00366 void KWindowSystem::demandAttention( WId win, bool set )
00367 {
00368
00369 kDebug(240) << "KWindowSystem::demandAttention( WId win, bool set ) isn't yet implemented!";
00370 }
00371
00372 bool KWindowSystem::compositingActive()
00373 {
00374 return false;
00375 }
00376
00377 int KWindowSystem::currentDesktop()
00378 {
00379 return 1;
00380 }
00381
00382 int KWindowSystem::numberOfDesktops()
00383 {
00384 return 1;
00385 }
00386
00387 void KWindowSystem::setCurrentDesktop( int desktop )
00388 {
00389 kDebug(240) << "KWindowSystem::setCurrentDesktop( int desktop ) isn't yet implemented!";
00390
00391 }
00392
00393 void KWindowSystem::setOnAllDesktops( WId win, bool b )
00394 {
00395 kDebug(240) << "KWindowSystem::setOnAllDesktops( WId win, bool b ) isn't yet implemented!";
00396
00397 }
00398
00399 void KWindowSystem::setOnDesktop( WId win, int desktop )
00400 {
00401
00402 kDebug(240) << "KWindowSystem::setOnDesktop( WId win, int desktop ) isn't yet implemented!";
00403 }
00404
00405 void KWindowSystem::setMainWindow( QWidget* subwindow, WId id )
00406 {
00407 kDebug(240) << "KWindowSystem::setMainWindow( QWidget*, WId ) isn't yet implemented!";
00408
00409 }
00410
00411 QPixmap KWindowSystem::icon( WId win, int width, int height, bool scale )
00412 {
00413 if (hasWId(win)) {
00414 KWindowInfo info = windowInfo(win, 0);
00415 if (!info.d->loadedData) {
00416 info.d->updateData();
00417 }
00418 IconRef icon;
00419 SInt16 label;
00420 if (GetIconRefFromFile(&info.d->iconSpec, &icon, &label)) {
00421 kDebug(240) << "Error getting icon from application";
00422 return QPixmap();
00423 } else {
00424 QPixmap ret(width, height);
00425 ret.fill(QColor(0, 0, 0, 0));
00426
00427 CGRect rect = CGRectMake(0, 0, width, height);
00428
00429 CGContextRef ctx = qt_mac_cg_context(&ret);
00430 CGAffineTransform old_xform = CGContextGetCTM(ctx);
00431 CGContextConcatCTM(ctx, CGAffineTransformInvert(old_xform));
00432 CGContextConcatCTM(ctx, CGAffineTransformIdentity);
00433
00434 ::RGBColor b;
00435 b.blue = b.green = b.red = 255*255;
00436 PlotIconRefInContext(ctx, &rect, kAlignNone, kTransformNone, &b, kPlotIconRefNormalFlags, icon);
00437 CGContextRelease(ctx);
00438
00439 ReleaseIconRef(icon);
00440 return ret;
00441 }
00442 } else {
00443 kDebug(240) << "QPixmap KWindowSystem::icon( WId win, int width, int height, bool scale ) isn't yet implemented for local windows!";
00444 return QPixmap();
00445 }
00446 }
00447
00448 QPixmap KWindowSystem::icon( WId win, int width, int height, bool scale, int flags )
00449 {
00450 return icon(win, width, height, scale);
00451
00452 }
00453
00454 void KWindowSystem::setIcons( WId win, const QPixmap& icon, const QPixmap& miniIcon )
00455 {
00456
00457 kDebug(240) << "KWindowSystem::setIcons( WId win, const QPixmap& icon, const QPixmap& miniIcon ) isn't yet implemented!";
00458 }
00459
00460 void KWindowSystem::setType( WId winid, NET::WindowType windowType )
00461 {
00462
00463 if (hasWId(winid)) return;
00464
00465 static WindowGroupRef desktopGroup = 0;
00466 static WindowGroupRef dockGroup = 0;
00467
00468 WindowRef win = HIViewGetWindow( (HIViewRef) winid );
00469
00470 if (windowType != NET::Desktop && windowType != NET::Dock) {
00471 kDebug(240) << "setType( WId win, NET::WindowType windowType ) isn't yet implemented for the type you requested!";
00472 }
00473 if (windowType == NET::Desktop) {
00474 if (!desktopGroup) {
00475 CreateWindowGroup(0, &desktopGroup);
00476 SetWindowGroupLevel(desktopGroup, kCGDesktopIconWindowLevel);
00477 }
00478 SetWindowGroup(win, desktopGroup);
00479 } else if (windowType == NET::Dock) {
00480 if (!dockGroup) {
00481 CreateWindowGroup(0, &dockGroup);
00482 SetWindowGroupLevel(dockGroup, kCGDockWindowLevel);
00483 }
00484 SetWindowGroup(win, dockGroup);
00485 ChangeWindowAttributes(win, kWindowNoTitleBarAttribute, kWindowNoAttributes);
00486 }
00487 }
00488
00489 void KWindowSystem::setState( WId win, unsigned long state )
00490 {
00491
00492 kDebug(240) << "KWindowSystem::setState( WId win, unsigned long state ) isn't yet implemented!";
00493 }
00494
00495 void KWindowSystem::clearState( WId win, unsigned long state )
00496 {
00497
00498 kDebug(240) << "KWindowSystem::clearState( WId win, unsigned long state ) isn't yet implemented!";
00499 }
00500
00501 void KWindowSystem::minimizeWindow( WId win, bool animation)
00502 {
00503
00504 kDebug(240) << "KWindowSystem::minimizeWindow( WId win, bool animation) isn't yet implemented!";
00505 }
00506
00507 void KWindowSystem::unminimizeWindow( WId win, bool animation )
00508 {
00509
00510 kDebug(240) << "KWindowSystem::unminimizeWindow( WId win, bool animation ) isn't yet implemented!";
00511 }
00512
00513 void KWindowSystem::raiseWindow( WId win )
00514 {
00515
00516 kDebug(240) << "KWindowSystem::raiseWindow( WId win ) isn't yet implemented!";
00517 }
00518
00519 void KWindowSystem::lowerWindow( WId win )
00520 {
00521
00522 kDebug(240) << "KWindowSystem::lowerWindow( WId win ) isn't yet implemented!";
00523 }
00524
00525 bool KWindowSystem::icccmCompliantMappingState()
00526 {
00527 return false;
00528 }
00529
00530 QRect KWindowSystem::workArea( int desktop )
00531 {
00532
00533 kDebug(240) << "QRect KWindowSystem::workArea( int desktop ) isn't yet implemented!";
00534 return QRect();
00535 }
00536
00537 QRect KWindowSystem::workArea( const QList<WId>& exclude, int desktop )
00538 {
00539
00540 kDebug(240) << "QRect KWindowSystem::workArea( const QList<WId>& exclude, int desktop ) isn't yet implemented!";
00541 return QRect();
00542 }
00543
00544 QString KWindowSystem::desktopName( int desktop )
00545 {
00546 return i18n("Desktop %1", desktop );
00547 }
00548
00549 void KWindowSystem::setDesktopName( int desktop, const QString& name )
00550 {
00551 kDebug(240) << "KWindowSystem::setDesktopName( int desktop, const QString& name ) isn't yet implemented!";
00552
00553 }
00554
00555 bool KWindowSystem::showingDesktop()
00556 {
00557 return false;
00558 }
00559
00560 void KWindowSystem::setUserTime( WId win, long time )
00561 {
00562 kDebug(240) << "KWindowSystem::setUserTime( WId win, long time ) isn't yet implemented!";
00563
00564 }
00565
00566 void KWindowSystem::setExtendedStrut( WId win, int left_width, int left_start, int left_end,
00567 int right_width, int right_start, int right_end, int top_width, int top_start, int top_end,
00568 int bottom_width, int bottom_start, int bottom_end )
00569 {
00570 kDebug(240) << "KWindowSystem::setExtendedStrut isn't yet implemented!";
00571
00572 }
00573
00574 void KWindowSystem::setStrut( WId win, int left, int right, int top, int bottom )
00575 {
00576 kDebug(240) << "KWindowSystem::setStrut isn't yet implemented!";
00577
00578 }
00579
00580 bool KWindowSystem::allowedActionsSupported()
00581 {
00582 return false;
00583 }
00584
00585 QString KWindowSystem::readNameProperty( WId window, unsigned long atom )
00586 {
00587
00588 kDebug(240) << "QString KWindowSystem::readNameProperty( WId window, unsigned long atom ) isn't yet implemented!";
00589 return QString();
00590 }
00591
00592 void KWindowSystem::doNotManage( const QString& title )
00593 {
00594
00595 kDebug(240) << "KWindowSystem::doNotManage( const QString& title ) isn't yet implemented!";
00596 }
00597
00598
00599 void KWindowSystem::connectNotify( const char* signal )
00600 {
00601 kDebug(240) << "connectNotify( const char* signal ) isn't yet implemented!";
00602
00603 }
00604
00605 #include "moc_kwindowsystem.cpp"