Permalink
Browse files

implemented QxtWindowSystem for Mac. Warning: for the most part

uses CoreGraphics *private* and *undocumented* features and may brake
at any time. Works with 10.6.x.
  • Loading branch information...
1 parent 512258b commit 602328cc1b1bf2274c2b74364add5c994170b718 @marcinjakubowski marcinjakubowski committed Nov 11, 2010
Showing with 304 additions and 3 deletions.
  1. +5 −3 src/gui/gui.pri
  2. +155 −0 src/gui/qxtwindowsystem_mac.cpp
  3. +144 −0 src/gui/qxtwindowsystem_mac.h
View
@@ -135,10 +135,13 @@ SOURCES += qxtlookuplineedit.cpp
SOURCES += qxtwindowsystem_x11.cpp
}
macx {
+ HEADERS += qxtwindowsystem_mac.h
SOURCES += qxtapplication_mac.cpp
SOURCES += qxtglobalshortcut_mac.cpp
- SOURCES -= qxtscreen.cpp qxtwindowsystem.cpp
- HEADERS -= qxtscreen.h qxtwindowsystem.h
+ SOURCES += qxtwindowsystem_mac.cpp
+
+ SOURCES -= qxtscreen.cpp
+ HEADERS -= qxtscreen.h
}
win32 {
SOURCES += qxtapplication_win.cpp
@@ -149,4 +152,3 @@ SOURCES += qxtlookuplineedit.cpp
}
RESOURCES += resources.qrc
-
@@ -0,0 +1,155 @@
+#ifndef QXTWINDOWSYSTEM_MAC_CPP
+#define QXTWINDOWSYSTEM_MAC_CPP
+
+#include "qxtwindowsystem.h"
+#include "qxtwindowsystem_mac.h"
+
+// WId to return when error
+#define WINDOW_NOT_FOUND (WId)(0)
+
+WindowList qxt_getWindowsForPSN(ProcessSerialNumber *psn)
+{
+ static CGSConnection connection = _CGSDefaultConnection();
+
+ WindowList wlist;
+ if (!psn) return wlist;
+
+ CGError err(noErr);
+
+ // get onnection for given process psn
+ CGSConnection procConnection;
+ err = CGSGetConnectionIDForPSN(connection, psn, &procConnection);
+ if (err != noErr) return wlist;
+
+ /* get number of windows open by given process
+ in Mac OS X an application may have multiple windows, which generally
+ represent documents. It is also possible that there is no window even
+ though there is an application, it can simply not have any documents open. */
+
+ int windowCount(0);
+ err = CGSGetOnScreenWindowCount(connection, procConnection, &windowCount);
+ // if there are no windows open by this application, skip
+ if (err != noErr || windowCount == 0) return wlist;
+
+ // get list of windows
+ int windowList[windowCount];
+ int outCount(0);
+ err = CGSGetOnScreenWindowList(connection, procConnection, windowCount, windowList, &outCount);
+
+ if (err != noErr || outCount == 0) return wlist;
+
+ for (int i=0; i<outCount; ++i)
+ {
+ wlist += windowList[i];
+ }
+
+ return wlist;
+}
+
+
+WindowList QxtWindowSystem::windows()
+{
+ WindowList wlist;
+ ProcessSerialNumber psn = {0, kNoProcess};
+
+ // iterate over list of processes
+ OSErr err;
+ while ((err = ::GetNextProcess(&psn)) == noErr)
+ {
+ wlist += qxt_getWindowsForPSN(&psn);
+ }
+
+ return wlist;
+}
+
+WId QxtWindowSystem::activeWindow()
+{
+ ProcessSerialNumber psn;
+ OSErr err(noErr);
+ err = ::GetFrontProcess(&psn);
+ if (err != noErr) return WINDOW_NOT_FOUND;
+
+ // in Mac OS X, first window for given PSN is always the active one
+ WindowList wlist = qxt_getWindowsForPSN(&psn);
+
+ if (wlist.count() > 0)
+ return wlist.at(0);
+
+ return WINDOW_NOT_FOUND;
+}
+
+QString QxtWindowSystem::windowTitle(WId window)
+{
+ CGSValue windowTitle;
+ CGError err(noErr);
+ static CGSConnection connection = _CGSDefaultConnection();
+
+ // This code is so dirty I had to wash my hands after writing it.
+
+ // most of CoreGraphics private definitions ask for CGSValue as key but since
+ // converting strings to/from CGSValue was dropped in 10.5, I use CFString, which
+ // apparently also works.
+ err = CGSGetWindowProperty(connection, window, (CGSValue)CFSTR("kCGSWindowTitle"), &windowTitle);
+ if (err != noErr) return QString();
+
+ // this is UTF8 encoded
+ return QCFString::toQString((CFStringRef)windowTitle);
+}
+
+QRect QxtWindowSystem::windowGeometry(WId window)
+{
+ CGRect rect;
+ static CGSConnection connection = _CGSDefaultConnection();
+
+ CGError err = CGSGetWindowBounds(connection, window, &rect);
+ if (err != noErr) return QRect();
+
+ return QRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
+}
+
+/* This method is the only one that is not a complete hack
+ from Quartz Event Services
+ http://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html
+*/
+uint QxtWindowSystem::idleTime()
+{
+ // CGEventSourceSecondsSinceLastEventType returns time in seconds as a double
+ // also has extremely long name
+ double idle = 1000 * ::CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGAnyInputEventType);
+ return (uint)idle;
+}
+
+
+// these are copied from X11 implementation
+WId QxtWindowSystem::findWindow(const QString& title)
+{
+ WId result = 0;
+ WindowList list = windows();
+ foreach(const WId &wid, list)
+ {
+ if (windowTitle(wid) == title)
+ {
+ result = wid;
+ break;
+ }
+ }
+ return result;
+}
+
+WId QxtWindowSystem::windowAt(const QPoint& pos)
+{
+ WId result = 0;
+ WindowList list = windows();
+ for (int i = list.size() - 1; i >= 0; --i)
+ {
+ WId wid = list.at(i);
+ if (windowGeometry(wid).contains(pos))
+ {
+ result = wid;
+ break;
+ }
+ }
+ return result;
+}
+
+#endif // QXTWINDOWSYSTEM_MAC_CPP
@@ -0,0 +1,144 @@
+/****************************************************************************
+ **
+ ** Copyright (C) Qxt Foundation. Some rights reserved.
+ **
+ ** This file is part of the QxtGui module of the Qxt library.
+ **
+ ** This library is free software; you can redistribute it and/or modify it
+ ** under the terms of the Common Public License, version 1.0, as published
+ ** by IBM, and/or under the terms of the GNU Lesser General Public License,
+ ** version 2.1, as published by the Free Software Foundation.
+ **
+ ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
+ ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
+ ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
+ ** FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ** You should have received a copy of the CPL and the LGPL along with this
+ ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
+ ** included with the source distribution for more information.
+ ** If you did not receive a copy of the licenses, contact the Qxt Foundation.
+ **
+ ** <http://libqxt.org> <foundation@libqxt.org>
+ **
+ ****************************************************************************/
+
+/****************************************************************************
+ **
+ ** Copyright (C) Marcin Jakubowski <mjakubowski (at) gmail (dot) com
+ **
+ ** Defines some of required CoreGraphics private parts. This code may
+ ** break at any time and uses *undocumented* features of Mac OS X.
+ **
+ ** Also defines QCFString, part of Qt code found in src/corelib/kernel
+ ** qcoremac_p.h file.
+ ****************************************************************************/
+
+#ifndef QXTWINDOWSYSTEM_MAC_H
+#define QXTWINDOWSYSTEM_MAC_H
+
+//
+// CGSPrivate.h
+// Header file for undocumented CoreGraphics SPI
+//
+// Arranged by Nicholas Jitkoff
+// Based on CGSPrivate.h by Richard Wareham
+//
+// Contributors:
+// Austin Sarner: Shadows
+// Jason Harris: Filters, Shadows, Regions
+// Kevin Ballard: Warping
+// Steve Voida: Workspace notifications
+// Tony Arnold: Workspaces notifications enum filters
+// Ben Gertzfield: CGSRemoveConnectionNotifyProc
+//
+// Changes:
+// 2.3 - Added the CGSRemoveConnectionNotifyProc method with the help of Ben Gertzfield
+// 2.2 - Moved back to CGSPrivate, added more enums to the CGSConnectionNotifyEvent
+// 2.1 - Added spaces notifications
+// 2.0 - Original Release
+
+#include <Carbon/Carbon.h>
+
+#define CGSConnectionID CGSConnection
+#define CGSWindowID CGSWindow
+#define CGSDefaultConnection _CGSDefaultConnection()
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ typedef int CGSConnection;
+ typedef int CGSWindow;
+ typedef int CGSWorkspace;
+ typedef void* CGSValue;
+
+ /* Get the default connection for the current process. */
+ extern CGSConnection _CGSDefaultConnection(void);
+
+ /* /MJakubowski/ Get connection for given PSN */
+ extern CGError CGSGetConnectionIDForPSN(const CGSConnection connection, ProcessSerialNumber * psn, CGSConnection * targetConnection);
+
+ // Get on-screen window counts and lists.
+ extern CGError CGSGetOnScreenWindowCount(const CGSConnection cid, CGSConnection targetCID, int* outCount);
+ extern CGError CGSGetOnScreenWindowList(const CGSConnection cid, CGSConnection targetCID, int count, int* list, int* outCount);
+ // Position
+ extern CGError CGSGetWindowBounds(CGSConnection cid, CGSWindowID wid, CGRect *outBounds);
+ extern CGError CGSGetScreenRectForWindow(const CGSConnection cid, CGSWindow wid, CGRect *outRect);
+
+ // Properties
+ extern CGError CGSGetWindowProperty(const CGSConnection cid, CGSWindow wid, CGSValue key, CGSValue *outValue);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+/* QCFString from Qt */
+#include <QString>
+template <typename T>
+class QCFType
+{
+public:
+ inline QCFType(const T &t = 0) : type(t) {}
+ inline QCFType(const QCFType &helper) : type(helper.type) { if (type) CFRetain(type); }
+ inline ~QCFType() { if (type) CFRelease(type); }
+ inline operator T() { return type; }
+ inline QCFType operator =(const QCFType &helper)
+ {
+ if (helper.type)
+ CFRetain(helper.type);
+ CFTypeRef type2 = type;
+ type = helper.type;
+ if (type2)
+ CFRelease(type2);
+ return *this;
+ }
+ inline T *operator&() { return &type; }
+ static QCFType constructFromGet(const T &t)
+ {
+ CFRetain(t);
+ return QCFType<T>(t);
+ }
+protected:
+ T type;
+};
+
+class QCFString : public QCFType<CFStringRef>
+{
+public:
+ inline QCFString(const QString &str) : QCFType<CFStringRef>(0), string(str) {}
+ inline QCFString(const CFStringRef cfstr = 0) : QCFType<CFStringRef>(cfstr) {}
+ inline QCFString(const QCFType<CFStringRef> &other) : QCFType<CFStringRef>(other) {}
+ operator QString() const;
+ operator CFStringRef() const;
+ static QString toQString(CFStringRef cfstr);
+ static CFStringRef toCFStringRef(const QString &str);
+private:
+ QString string;
+};
+
+
+
+
+#endif // QXTWINDOWSYSTEM_MAC_H

0 comments on commit 602328c

Please sign in to comment.