diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch) | |
tree | 5ac38a06f3dde268dc7927dc155896926aaf7012 /kdecore/netwm.cpp | |
download | tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kdecore/netwm.cpp')
-rw-r--r-- | kdecore/netwm.cpp | 4634 |
1 files changed, 4634 insertions, 0 deletions
diff --git a/kdecore/netwm.cpp b/kdecore/netwm.cpp new file mode 100644 index 000000000..e0685abc7 --- /dev/null +++ b/kdecore/netwm.cpp @@ -0,0 +1,4634 @@ +/* + + Copyright (c) 2000 Troll Tech AS + Copyright (c) 2003 Lubos Lunak <l.lunak@kde.org> + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + +*/ + +//#define NETWMDEBUG + +#include <qwidget.h> +#ifdef Q_WS_X11 //FIXME + +#include "netwm.h" + +#include <string.h> +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> + +#include <X11/Xmd.h> + +#include "netwm_p.h" + +// UTF-8 string +static Atom UTF8_STRING = 0; + +// root window properties +static Atom net_supported = 0; +static Atom net_client_list = 0; +static Atom net_client_list_stacking = 0; +static Atom net_desktop_geometry = 0; +static Atom net_desktop_viewport = 0; +static Atom net_current_desktop = 0; +static Atom net_desktop_names = 0; +static Atom net_number_of_desktops = 0; +static Atom net_active_window = 0; +static Atom net_workarea = 0; +static Atom net_supporting_wm_check = 0; +static Atom net_virtual_roots = 0; +static Atom net_showing_desktop = 0; +static Atom net_desktop_layout = 0; + +// root window messages +static Atom net_close_window = 0; +static Atom net_restack_window = 0; +static Atom net_wm_moveresize = 0; +static Atom net_moveresize_window = 0; + +// application window properties +static Atom net_wm_name = 0; +static Atom net_wm_visible_name = 0; +static Atom net_wm_icon_name = 0; +static Atom net_wm_visible_icon_name = 0; +static Atom net_wm_desktop = 0; +static Atom net_wm_window_type = 0; +static Atom net_wm_state = 0; +static Atom net_wm_strut = 0; +static Atom net_wm_extended_strut = 0; // the atom is called _NET_WM_STRUT_PARTIAL +static Atom net_wm_icon_geometry = 0; +static Atom net_wm_icon = 0; +static Atom net_wm_pid = 0; +static Atom net_wm_user_time = 0; +static Atom net_wm_handled_icons = 0; +static Atom net_startup_id = 0; +static Atom net_wm_allowed_actions = 0; +static Atom wm_window_role = 0; +static Atom net_frame_extents = 0; + +// KDE extensions +static Atom kde_net_system_tray_windows = 0; +static Atom kde_net_wm_system_tray_window_for = 0; +static Atom kde_net_wm_frame_strut = 0; +static Atom kde_net_wm_window_type_override = 0; +static Atom kde_net_wm_window_type_topmenu = 0; +static Atom kde_net_wm_temporary_rules = 0; + +// application protocols +static Atom wm_protocols = 0; +static Atom net_wm_ping = 0; +static Atom net_wm_take_activity = 0; + +// application window types +static Atom net_wm_window_type_normal = 0; +static Atom net_wm_window_type_desktop = 0; +static Atom net_wm_window_type_dock = 0; +static Atom net_wm_window_type_toolbar = 0; +static Atom net_wm_window_type_menu = 0; +static Atom net_wm_window_type_dialog = 0; +static Atom net_wm_window_type_utility = 0; +static Atom net_wm_window_type_splash = 0; +static Atom net_wm_window_type_dropdown_menu = 0; +static Atom net_wm_window_type_popup_menu = 0; +static Atom net_wm_window_type_tooltip = 0; +static Atom net_wm_window_type_notification = 0; +static Atom net_wm_window_type_combobox = 0; +static Atom net_wm_window_type_dnd = 0; + +// application window state +static Atom net_wm_state_modal = 0; +static Atom net_wm_state_sticky = 0; +static Atom net_wm_state_max_vert = 0; +static Atom net_wm_state_max_horiz = 0; +static Atom net_wm_state_shaded = 0; +static Atom net_wm_state_skip_taskbar = 0; +static Atom net_wm_state_skip_pager = 0; +static Atom net_wm_state_hidden = 0; +static Atom net_wm_state_fullscreen = 0; +static Atom net_wm_state_above = 0; +static Atom net_wm_state_below = 0; +static Atom net_wm_state_demands_attention = 0; + +// allowed actions +static Atom net_wm_action_move = 0; +static Atom net_wm_action_resize = 0; +static Atom net_wm_action_minimize = 0; +static Atom net_wm_action_shade = 0; +static Atom net_wm_action_stick = 0; +static Atom net_wm_action_max_vert = 0; +static Atom net_wm_action_max_horiz = 0; +static Atom net_wm_action_fullscreen = 0; +static Atom net_wm_action_change_desk = 0; +static Atom net_wm_action_close = 0; + +// KDE extension that's not in the specs - Replaced by state_above now? +static Atom net_wm_state_stays_on_top = 0; + +// used to determine whether application window is managed or not +static Atom xa_wm_state = 0; + +static Bool netwm_atoms_created = False; +const unsigned long netwm_sendevent_mask = (SubstructureRedirectMask| + SubstructureNotifyMask); + + +const long MAX_PROP_SIZE = 100000; + +static char *nstrdup(const char *s1) { + if (! s1) return (char *) 0; + + int l = strlen(s1) + 1; + char *s2 = new char[l]; + strncpy(s2, s1, l); + return s2; +} + + +static char *nstrndup(const char *s1, int l) { + if (! s1 || l == 0) return (char *) 0; + + char *s2 = new char[l+1]; + strncpy(s2, s1, l); + s2[l] = '\0'; + return s2; +} + + +static Window *nwindup(Window *w1, int n) { + if (! w1 || n == 0) return (Window *) 0; + + Window *w2 = new Window[n]; + while (n--) w2[n] = w1[n]; + return w2; +} + + +static void refdec_nri(NETRootInfoPrivate *p) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NET: decrementing NETRootInfoPrivate::ref (%d)\n", p->ref - 1); +#endif + + if (! --p->ref) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NET: \tno more references, deleting\n"); +#endif + + delete [] p->name; + delete [] p->stacking; + delete [] p->clients; + delete [] p->virtual_roots; + delete [] p->kde_system_tray_windows; + + int i; + for (i = 0; i < p->desktop_names.size(); i++) + delete [] p->desktop_names[i]; + } +} + + +static void refdec_nwi(NETWinInfoPrivate *p) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NET: decrementing NETWinInfoPrivate::ref (%d)\n", p->ref - 1); +#endif + + if (! --p->ref) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NET: \tno more references, deleting\n"); +#endif + + delete [] p->name; + delete [] p->visible_name; + delete [] p->icon_name; + delete [] p->visible_icon_name; + delete [] p->startup_id; + + int i; + for (i = 0; i < p->icons.size(); i++) + delete [] p->icons[i].data; + } +} + + +static int wcmp(const void *a, const void *b) { + return *((Window *) a) - *((Window *) b); +} + + +static const int netAtomCount = 84; +static void create_atoms(Display *d) { + static const char * const names[netAtomCount] = + { + "UTF8_STRING", + "_NET_SUPPORTED", + "_NET_SUPPORTING_WM_CHECK", + "_NET_CLIENT_LIST", + "_NET_CLIENT_LIST_STACKING", + "_NET_NUMBER_OF_DESKTOPS", + "_NET_DESKTOP_GEOMETRY", + "_NET_DESKTOP_VIEWPORT", + "_NET_CURRENT_DESKTOP", + "_NET_DESKTOP_NAMES", + "_NET_ACTIVE_WINDOW", + "_NET_WORKAREA", + "_NET_VIRTUAL_ROOTS", + "_NET_DESKTOP_LAYOUT", + "_NET_SHOWING_DESKTOP", + "_NET_CLOSE_WINDOW", + "_NET_RESTACK_WINDOW", + + "_NET_WM_MOVERESIZE", + "_NET_MOVERESIZE_WINDOW", + "_NET_WM_NAME", + "_NET_WM_VISIBLE_NAME", + "_NET_WM_ICON_NAME", + "_NET_WM_VISIBLE_ICON_NAME", + "_NET_WM_DESKTOP", + "_NET_WM_WINDOW_TYPE", + "_NET_WM_STATE", + "_NET_WM_STRUT", + "_NET_WM_STRUT_PARTIAL", + "_NET_WM_ICON_GEOMETRY", + "_NET_WM_ICON", + "_NET_WM_PID", + "_NET_WM_USER_TIME", + "_NET_WM_HANDLED_ICONS", + "_NET_STARTUP_ID", + "_NET_WM_ALLOWED_ACTIONS", + "_NET_WM_PING", + "_NET_WM_TAKE_ACTIVITY", + "WM_WINDOW_ROLE", + "_NET_FRAME_EXTENTS", + + "_NET_WM_WINDOW_TYPE_NORMAL", + "_NET_WM_WINDOW_TYPE_DESKTOP", + "_NET_WM_WINDOW_TYPE_DOCK", + "_NET_WM_WINDOW_TYPE_TOOLBAR", + "_NET_WM_WINDOW_TYPE_MENU", + "_NET_WM_WINDOW_TYPE_DIALOG", + "_NET_WM_WINDOW_TYPE_UTILITY", + "_NET_WM_WINDOW_TYPE_SPLASH", + "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", + "_NET_WM_WINDOW_TYPE_POPUP_MENU", + "_NET_WM_WINDOW_TYPE_TOOLTIP", + "_NET_WM_WINDOW_TYPE_NOTIFICATION", + "_NET_WM_WINDOW_TYPE_COMBOBOX", + "_NET_WM_WINDOW_TYPE_DND", + + "_NET_WM_STATE_MODAL", + "_NET_WM_STATE_STICKY", + "_NET_WM_STATE_MAXIMIZED_VERT", + "_NET_WM_STATE_MAXIMIZED_HORZ", + "_NET_WM_STATE_SHADED", + "_NET_WM_STATE_SKIP_TASKBAR", + "_NET_WM_STATE_SKIP_PAGER", + "_NET_WM_STATE_HIDDEN", + "_NET_WM_STATE_FULLSCREEN", + "_NET_WM_STATE_ABOVE", + "_NET_WM_STATE_BELOW", + "_NET_WM_STATE_DEMANDS_ATTENTION", + + "_NET_WM_ACTION_MOVE", + "_NET_WM_ACTION_RESIZE", + "_NET_WM_ACTION_MINIMIZE", + "_NET_WM_ACTION_SHADE", + "_NET_WM_ACTION_STICK", + "_NET_WM_ACTION_MAXIMIZE_VERT", + "_NET_WM_ACTION_MAXIMIZE_HORZ", + "_NET_WM_ACTION_FULLSCREEN", + "_NET_WM_ACTION_CHANGE_DESKTOP", + "_NET_WM_ACTION_CLOSE", + + "_NET_WM_STATE_STAYS_ON_TOP", + + "_KDE_NET_SYSTEM_TRAY_WINDOWS", + "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", + "_KDE_NET_WM_FRAME_STRUT", + "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", + "_KDE_NET_WM_WINDOW_TYPE_TOPMENU", + "_KDE_NET_WM_TEMPORARY_RULES", + + "WM_STATE", + "WM_PROTOCOLS" + }; + + Atom atoms[netAtomCount], *atomsp[netAtomCount] = + { + &UTF8_STRING, + &net_supported, + &net_supporting_wm_check, + &net_client_list, + &net_client_list_stacking, + &net_number_of_desktops, + &net_desktop_geometry, + &net_desktop_viewport, + &net_current_desktop, + &net_desktop_names, + &net_active_window, + &net_workarea, + &net_virtual_roots, + &net_desktop_layout, + &net_showing_desktop, + &net_close_window, + &net_restack_window, + + &net_wm_moveresize, + &net_moveresize_window, + &net_wm_name, + &net_wm_visible_name, + &net_wm_icon_name, + &net_wm_visible_icon_name, + &net_wm_desktop, + &net_wm_window_type, + &net_wm_state, + &net_wm_strut, + &net_wm_extended_strut, + &net_wm_icon_geometry, + &net_wm_icon, + &net_wm_pid, + &net_wm_user_time, + &net_wm_handled_icons, + &net_startup_id, + &net_wm_allowed_actions, + &net_wm_ping, + &net_wm_take_activity, + &wm_window_role, + &net_frame_extents, + + &net_wm_window_type_normal, + &net_wm_window_type_desktop, + &net_wm_window_type_dock, + &net_wm_window_type_toolbar, + &net_wm_window_type_menu, + &net_wm_window_type_dialog, + &net_wm_window_type_utility, + &net_wm_window_type_splash, + &net_wm_window_type_dropdown_menu, + &net_wm_window_type_popup_menu, + &net_wm_window_type_tooltip, + &net_wm_window_type_notification, + &net_wm_window_type_combobox, + &net_wm_window_type_dnd, + + &net_wm_state_modal, + &net_wm_state_sticky, + &net_wm_state_max_vert, + &net_wm_state_max_horiz, + &net_wm_state_shaded, + &net_wm_state_skip_taskbar, + &net_wm_state_skip_pager, + &net_wm_state_hidden, + &net_wm_state_fullscreen, + &net_wm_state_above, + &net_wm_state_below, + &net_wm_state_demands_attention, + + &net_wm_action_move, + &net_wm_action_resize, + &net_wm_action_minimize, + &net_wm_action_shade, + &net_wm_action_stick, + &net_wm_action_max_vert, + &net_wm_action_max_horiz, + &net_wm_action_fullscreen, + &net_wm_action_change_desk, + &net_wm_action_close, + + &net_wm_state_stays_on_top, + + &kde_net_system_tray_windows, + &kde_net_wm_system_tray_window_for, + &kde_net_wm_frame_strut, + &kde_net_wm_window_type_override, + &kde_net_wm_window_type_topmenu, + &kde_net_wm_temporary_rules, + + &xa_wm_state, + &wm_protocols + }; + + assert( !netwm_atoms_created ); + + int i = netAtomCount; + while (i--) + atoms[i] = 0; + + XInternAtoms(d, (char **) names, netAtomCount, False, atoms); + + i = netAtomCount; + while (i--) + *atomsp[i] = atoms[i]; + + netwm_atoms_created = True; +} + + +static void readIcon(Display* display, Window window, Atom property, NETRArray<NETIcon>& icons, int& icon_count) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NET: readIcon\n"); +#endif + + Atom type_ret; + int format_ret; + unsigned long nitems_ret = 0, after_ret = 0; + unsigned char *data_ret = 0; + + // reset + for (int i = 0; i < icons.size(); i++) + delete [] icons[i].data; + icons.reset(); + icon_count = 0; + + // allocate buffers + unsigned char *buffer = 0; + unsigned long offset = 0; + unsigned long buffer_offset = 0; + unsigned long bufsize = 0; + + // read data + do { + if (XGetWindowProperty(display, window, property, offset, + MAX_PROP_SIZE, False, XA_CARDINAL, &type_ret, + &format_ret, &nitems_ret, &after_ret, &data_ret) + == Success) { + if (!bufsize) + { + if (nitems_ret < 3 || type_ret != XA_CARDINAL || + format_ret != 32) { + // either we didn't get the property, or the property has less than + // 3 elements in it + // NOTE: 3 is the ABSOLUTE minimum: + // width = 1, height = 1, length(data) = 1 (width * height) + if ( data_ret ) + XFree(data_ret); + return; + } + + bufsize = nitems_ret * sizeof(long) + after_ret; + buffer = (unsigned char *) malloc(bufsize); + } + else if (buffer_offset + nitems_ret*sizeof(long) > bufsize) + { +fprintf(stderr, "NETWM: Warning readIcon() needs buffer adjustment!\n"); + bufsize = buffer_offset + nitems_ret * sizeof(long) + after_ret; + buffer = (unsigned char *) realloc(buffer, bufsize); + } + memcpy((buffer + buffer_offset), data_ret, nitems_ret * sizeof(long)); + buffer_offset += nitems_ret * sizeof(long); + offset += nitems_ret; + + if ( data_ret ) + XFree(data_ret); + } else { + if (buffer) + free(buffer); + return; // Some error occurred cq. property didn't exist. + } + } + while (after_ret > 0); + + CARD32 *data32; + unsigned long i, j, k, sz, s; + unsigned long *d = (unsigned long *) buffer; + for (i = 0, j = 0; i < bufsize;) { + icons[j].size.width = *d++; + i += sizeof(long); + icons[j].size.height = *d++; + i += sizeof(long); + + sz = icons[j].size.width * icons[j].size.height; + s = sz * sizeof(long); + + if ( i + s - 1 > bufsize || sz == 0 || sz > 1024 * 1024 ) { + break; + } + + delete [] icons[j].data; + data32 = new CARD32[sz]; + icons[j].data = (unsigned char *) data32; + for (k = 0; k < sz; k++, i += sizeof(long)) { + *data32++ = (CARD32) *d++; + } + j++; + icon_count++; + } + +#ifdef NETWMDEBUG + fprintf(stderr, "NET: readIcon got %d icons\n", icon_count); +#endif + + free(buffer); +} + + +template <class Z> +NETRArray<Z>::NETRArray() + : sz(0), capacity(2) +{ + d = (Z*) calloc(capacity, sizeof(Z)); // allocate 2 elts and set to zero +} + + +template <class Z> +NETRArray<Z>::~NETRArray() { + free(d); +} + + +template <class Z> +void NETRArray<Z>::reset() { + sz = 0; + capacity = 2; + d = (Z*) realloc(d, sizeof(Z)*capacity); + memset( (void*) d, 0, sizeof(Z)*capacity ); +} + +template <class Z> +Z &NETRArray<Z>::operator[](int index) { + if (index >= capacity) { + // allocate space for the new data + // open table has amortized O(1) access time + // when N elements appended consecutively -- exa + int newcapacity = 2*capacity > index+1 ? 2*capacity : index+1; // max + // copy into new larger memory block using realloc + d = (Z*) realloc(d, sizeof(Z)*newcapacity); + memset( (void*) &d[capacity], 0, sizeof(Z)*(newcapacity-capacity) ); + capacity = newcapacity; + } + if (index >= sz) // at this point capacity>index + sz = index + 1; + + return d[index]; +} + + +// Construct a new NETRootInfo object. + +NETRootInfo::NETRootInfo(Display *display, Window supportWindow, const char *wmName, + const unsigned long properties[], int properties_size, + int screen, bool doActivate) +{ + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::NETRootInfo: using window manager constructor\n"); +#endif + + p = new NETRootInfoPrivate; + p->ref = 1; + + p->display = display; + p->name = nstrdup(wmName); + + if (screen != -1) { + p->screen = screen; + } else { + p->screen = DefaultScreen(p->display); + } + + p->root = RootWindow(p->display, p->screen); + p->supportwindow = supportWindow; + p->number_of_desktops = p->current_desktop = 0; + p->active = None; + p->clients = p->stacking = p->virtual_roots = (Window *) 0; + p->clients_count = p->stacking_count = p->virtual_roots_count = 0; + p->kde_system_tray_windows = 0; + p->kde_system_tray_windows_count = 0; + p->showing_desktop = false; + p->desktop_layout_orientation = OrientationHorizontal; + p->desktop_layout_corner = DesktopLayoutCornerTopLeft; + p->desktop_layout_columns = p->desktop_layout_rows = 0; + setDefaultProperties(); + if( properties_size > PROPERTIES_SIZE ) { + fprintf( stderr, "NETRootInfo::NETRootInfo(): properties array too large\n"); + properties_size = PROPERTIES_SIZE; + } + for( int i = 0; i < properties_size; ++i ) + p->properties[ i ] = properties[ i ]; + // force support for Supported and SupportingWMCheck for window managers + p->properties[ PROTOCOLS ] |= ( Supported | SupportingWMCheck ); + p->client_properties[ PROTOCOLS ] = DesktopNames // the only thing that can be changed by clients + | WMPing; // or they can reply to this + p->client_properties[ PROTOCOLS2 ] = WM2TakeActivity | WM2DesktopLayout; + + role = WindowManager; + + if (! netwm_atoms_created) create_atoms(p->display); + + if (doActivate) activate(); +} + +NETRootInfo::NETRootInfo(Display *display, Window supportWindow, const char *wmName, + unsigned long properties, int screen, bool doActivate) +{ + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::NETRootInfo: using window manager constructor\n"); +#endif + + p = new NETRootInfoPrivate; + p->ref = 1; + + p->display = display; + p->name = nstrdup(wmName); + + if (screen != -1) { + p->screen = screen; + } else { + p->screen = DefaultScreen(p->display); + } + + p->root = RootWindow(p->display, p->screen); + p->supportwindow = supportWindow; + p->number_of_desktops = p->current_desktop = 0; + p->active = None; + p->clients = p->stacking = p->virtual_roots = (Window *) 0; + p->clients_count = p->stacking_count = p->virtual_roots_count = 0; + p->kde_system_tray_windows = 0; + p->kde_system_tray_windows_count = 0; + p->showing_desktop = false; + setDefaultProperties(); + p->properties[ PROTOCOLS ] = properties; + // force support for Supported and SupportingWMCheck for window managers + p->properties[ PROTOCOLS ] |= ( Supported | SupportingWMCheck ); + p->client_properties[ PROTOCOLS ] = DesktopNames // the only thing that can be changed by clients + | WMPing; // or they can reply to this + p->client_properties[ PROTOCOLS2 ] = WM2TakeActivity; + + role = WindowManager; + + if (! netwm_atoms_created) create_atoms(p->display); + + if (doActivate) activate(); +} + + +NETRootInfo::NETRootInfo(Display *display, const unsigned long properties[], int properties_size, + int screen, bool doActivate) +{ + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::NETRootInfo: using Client constructor\n"); +#endif + + p = new NETRootInfoPrivate; + p->ref = 1; + + p->name = 0; + + p->display = display; + + if (screen != -1) { + p->screen = screen; + } else { + p->screen = DefaultScreen(p->display); + } + + p->root = RootWindow(p->display, p->screen); + p->rootSize.width = WidthOfScreen(ScreenOfDisplay(p->display, p->screen)); + p->rootSize.height = HeightOfScreen(ScreenOfDisplay(p->display, p->screen)); + + p->supportwindow = None; + p->number_of_desktops = p->current_desktop = 0; + p->active = None; + p->clients = p->stacking = p->virtual_roots = (Window *) 0; + p->clients_count = p->stacking_count = p->virtual_roots_count = 0; + p->kde_system_tray_windows = 0; + p->kde_system_tray_windows_count = 0; + p->showing_desktop = false; + p->desktop_layout_orientation = OrientationHorizontal; + p->desktop_layout_corner = DesktopLayoutCornerTopLeft; + p->desktop_layout_columns = p->desktop_layout_rows = 0; + setDefaultProperties(); + if( properties_size > 2 ) { + fprintf( stderr, "NETWinInfo::NETWinInfo(): properties array too large\n"); + properties_size = 2; + } + for( int i = 0; i < properties_size; ++i ) + // remap from [0]=NET::Property,[1]=NET::Property2 + switch( i ) { + case 0: + p->client_properties[ PROTOCOLS ] = properties[ i ]; + break; + case 1: + p->client_properties[ PROTOCOLS2 ] = properties[ i ]; + break; + } + for( int i = 0; i < PROPERTIES_SIZE; ++i ) + p->properties[ i ] = 0; + + role = Client; + + if (! netwm_atoms_created) create_atoms(p->display); + + if (doActivate) activate(); +} + +NETRootInfo::NETRootInfo(Display *display, unsigned long properties, int screen, + bool doActivate) +{ + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::NETRootInfo: using Client constructor\n"); +#endif + + p = new NETRootInfoPrivate; + p->ref = 1; + + p->name = 0; + + p->display = display; + + if (screen != -1) { + p->screen = screen; + } else { + p->screen = DefaultScreen(p->display); + } + + p->root = RootWindow(p->display, p->screen); + p->rootSize.width = WidthOfScreen(ScreenOfDisplay(p->display, p->screen)); + p->rootSize.height = HeightOfScreen(ScreenOfDisplay(p->display, p->screen)); + + p->supportwindow = None; + p->number_of_desktops = p->current_desktop = 0; + p->active = None; + p->clients = p->stacking = p->virtual_roots = (Window *) 0; + p->clients_count = p->stacking_count = p->virtual_roots_count = 0; + p->kde_system_tray_windows = 0; + p->kde_system_tray_windows_count = 0; + p->showing_desktop = false; + p->desktop_layout_orientation = OrientationHorizontal; + p->desktop_layout_corner = DesktopLayoutCornerTopLeft; + p->desktop_layout_columns = p->desktop_layout_rows = 0; + setDefaultProperties(); + p->client_properties[ PROTOCOLS ] = properties; + for( int i = 0; i < PROPERTIES_SIZE; ++i ) + p->properties[ i ] = 0; + + role = Client; + + if (! netwm_atoms_created) create_atoms(p->display); + + if (doActivate) activate(); +} + + +NETRootInfo2::NETRootInfo2(Display *display, Window supportWindow, const char *wmName, + unsigned long properties[], int properties_size, + int screen, bool doActivate) + : NETRootInfo( display, supportWindow, wmName, properties, properties_size, + screen, doActivate ) +{ +} + +NETRootInfo2::NETRootInfo2(Display *display, const unsigned long properties[], int properties_size, + int screen, bool doActivate) + : NETRootInfo( display, properties, properties_size, screen, doActivate ) +{ +} + +NETRootInfo3::NETRootInfo3(Display *display, Window supportWindow, const char *wmName, + unsigned long properties[], int properties_size, + int screen, bool doActivate) + : NETRootInfo2( display, supportWindow, wmName, properties, properties_size, + screen, doActivate ) +{ +} + +NETRootInfo3::NETRootInfo3(Display *display, const unsigned long properties[], int properties_size, + int screen, bool doActivate) + : NETRootInfo2( display, properties, properties_size, screen, doActivate ) +{ +} + +NETRootInfo4::NETRootInfo4(Display *display, Window supportWindow, const char *wmName, + unsigned long properties[], int properties_size, + int screen, bool doActivate) + : NETRootInfo3( display, supportWindow, wmName, properties, properties_size, + screen, doActivate ) +{ +} + +NETRootInfo4::NETRootInfo4(Display *display, const unsigned long properties[], int properties_size, + int screen, bool doActivate) + : NETRootInfo3( display, properties, properties_size, screen, doActivate ) +{ +} + +// Copy an existing NETRootInfo object. + +NETRootInfo::NETRootInfo(const NETRootInfo &rootinfo) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::NETRootInfo: using copy constructor\n"); +#endif + + p = rootinfo.p; + role = rootinfo.role; + + p->ref++; +} + + +// Be gone with our NETRootInfo. + +NETRootInfo::~NETRootInfo() { + refdec_nri(p); + + if (! p->ref) delete p; +} + + +void NETRootInfo::setDefaultProperties() +{ + p->properties[ PROTOCOLS ] = Supported | SupportingWMCheck; + p->properties[ WINDOW_TYPES ] = NormalMask | DesktopMask | DockMask + | ToolbarMask | MenuMask | DialogMask; + p->properties[ STATES ] = Modal | Sticky | MaxVert | MaxHoriz | Shaded + | SkipTaskbar | StaysOnTop; + p->properties[ PROTOCOLS2 ] = 0; + p->properties[ ACTIONS ] = 0; + p->client_properties[ PROTOCOLS ] = 0; + p->client_properties[ WINDOW_TYPES ] = 0; // these two actually don't + p->client_properties[ STATES ] = 0; // make sense in client_properties + p->client_properties[ PROTOCOLS2 ] = 0; + p->client_properties[ ACTIONS ] = 0; +} + +void NETRootInfo::activate() { + if (role == WindowManager) { + +#ifdef NETWMDEBUG + fprintf(stderr, + "NETRootInfo::activate: setting supported properties on root\n"); +#endif + + setSupported(); + update(p->client_properties); + } else { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::activate: updating client information\n"); +#endif + + update(p->client_properties); + } +} + + +void NETRootInfo::setClientList(Window *windows, unsigned int count) { + if (role != WindowManager) return; + + p->clients_count = count; + + delete [] p->clients; + p->clients = nwindup(windows, count); + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::setClientList: setting list with %ld windows\n", + p->clients_count); +#endif + + XChangeProperty(p->display, p->root, net_client_list, XA_WINDOW, 32, + PropModeReplace, (unsigned char *)p->clients, + p->clients_count); +} + + +void NETRootInfo::setClientListStacking(Window *windows, unsigned int count) { + if (role != WindowManager) return; + + p->stacking_count = count; + delete [] p->stacking; + p->stacking = nwindup(windows, count); + +#ifdef NETWMDEBUG + fprintf(stderr, + "NETRootInfo::setClientListStacking: setting list with %ld windows\n", + p->clients_count); +#endif + + XChangeProperty(p->display, p->root, net_client_list_stacking, XA_WINDOW, 32, + PropModeReplace, (unsigned char *) p->stacking, + p->stacking_count); +} + + +void NETRootInfo::setKDESystemTrayWindows(Window *windows, unsigned int count) { + if (role != WindowManager) return; + + p->kde_system_tray_windows_count = count; + delete [] p->kde_system_tray_windows; + p->kde_system_tray_windows = nwindup(windows, count); + +#ifdef NETWMDEBUG + fprintf(stderr, + "NETRootInfo::setKDESystemTrayWindows: setting list with %ld windows\n", + p->kde_system_tray_windows_count); +#endif + + XChangeProperty(p->display, p->root, kde_net_system_tray_windows, XA_WINDOW, 32, + PropModeReplace, + (unsigned char *) p->kde_system_tray_windows, + p->kde_system_tray_windows_count); +} + + +void NETRootInfo::setNumberOfDesktops(int numberOfDesktops) { + +#ifdef NETWMDEBUG + fprintf(stderr, + "NETRootInfo::setNumberOfDesktops: setting desktop count to %d (%s)\n", + numberOfDesktops, (role == WindowManager) ? "WM" : "Client"); +#endif + + if (role == WindowManager) { + p->number_of_desktops = numberOfDesktops; + long d = numberOfDesktops; + XChangeProperty(p->display, p->root, net_number_of_desktops, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) &d, 1); + } else { + XEvent e; + + e.xclient.type = ClientMessage; + e.xclient.message_type = net_number_of_desktops; + e.xclient.display = p->display; + e.xclient.window = p->root; + e.xclient.format = 32; + e.xclient.data.l[0] = numberOfDesktops; + e.xclient.data.l[1] = 0l; + e.xclient.data.l[2] = 0l; + e.xclient.data.l[3] = 0l; + e.xclient.data.l[4] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } +} + + +void NETRootInfo::setCurrentDesktop(int desktop) { + +#ifdef NETWMDEBUG + fprintf(stderr, + "NETRootInfo::setCurrentDesktop: setting current desktop = %d (%s)\n", + desktop, (role == WindowManager) ? "WM" : "Client"); +#endif + + if (role == WindowManager) { + p->current_desktop = desktop; + long d = p->current_desktop - 1; + XChangeProperty(p->display, p->root, net_current_desktop, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) &d, 1); + } else { + XEvent e; + + e.xclient.type = ClientMessage; + e.xclient.message_type = net_current_desktop; + e.xclient.display = p->display; + e.xclient.window = p->root; + e.xclient.format = 32; + e.xclient.data.l[0] = desktop - 1; + e.xclient.data.l[1] = 0l; + e.xclient.data.l[2] = 0l; + e.xclient.data.l[3] = 0l; + e.xclient.data.l[4] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } +} + + +void NETRootInfo::setDesktopName(int desktop, const char *desktopName) { + // allow setting desktop names even for non-existant desktops, see the spec, sect.3.7. + if (desktop < 1) return; + + delete [] p->desktop_names[desktop - 1]; + p->desktop_names[desktop - 1] = nstrdup(desktopName); + + unsigned int i, proplen, + num = ((p->number_of_desktops > p->desktop_names.size()) ? + p->number_of_desktops : p->desktop_names.size()); + for (i = 0, proplen = 0; i < num; i++) + proplen += (p->desktop_names[i] != 0 ? strlen(p->desktop_names[i])+1 : 1 ); + + char *prop = new char[proplen], *propp = prop; + + for (i = 0; i < num; i++) + if (p->desktop_names[i]) { + strcpy(propp, p->desktop_names[i]); + propp += strlen(p->desktop_names[i]) + 1; + } else + *propp++ = '\0'; + +#ifdef NETWMDEBUG + fprintf(stderr, + "NETRootInfo::setDesktopName(%d, '%s')\n" + "NETRootInfo::setDesktopName: total property length = %d", + desktop, desktopName, proplen); +#endif + + XChangeProperty(p->display, p->root, net_desktop_names, UTF8_STRING, 8, + PropModeReplace, (unsigned char *) prop, proplen); + + delete [] prop; +} + + +void NETRootInfo::setDesktopGeometry(int , const NETSize &geometry) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::setDesktopGeometry( -- , { %d, %d }) (%s)\n", + geometry.width, geometry.height, (role == WindowManager) ? "WM" : "Client"); +#endif + + if (role == WindowManager) { + p->geometry = geometry; + + long data[2]; + data[0] = p->geometry.width; + data[1] = p->geometry.height; + + XChangeProperty(p->display, p->root, net_desktop_geometry, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) data, 2); + } else { + XEvent e; + + e.xclient.type = ClientMessage; + e.xclient.message_type = net_desktop_geometry; + e.xclient.display = p->display; + e.xclient.window = p->root; + e.xclient.format = 32; + e.xclient.data.l[0] = geometry.width; + e.xclient.data.l[1] = geometry.height; + e.xclient.data.l[2] = 0l; + e.xclient.data.l[3] = 0l; + e.xclient.data.l[4] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } +} + + +void NETRootInfo::setDesktopViewport(int desktop, const NETPoint &viewport) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::setDesktopViewport(%d, { %d, %d }) (%s)\n", + desktop, viewport.x, viewport.y, (role == WindowManager) ? "WM" : "Client"); +#endif + + if (desktop < 1) return; + + if (role == WindowManager) { + p->viewport[desktop - 1] = viewport; + + int d, i, l; + l = p->number_of_desktops * 2; + long *data = new long[l]; + for (d = 0, i = 0; d < p->number_of_desktops; d++) { + data[i++] = p->viewport[d].x; + data[i++] = p->viewport[d].y; + } + + XChangeProperty(p->display, p->root, net_desktop_viewport, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) data, l); + + delete [] data; + } else { + XEvent e; + + e.xclient.type = ClientMessage; + e.xclient.message_type = net_desktop_viewport; + e.xclient.display = p->display; + e.xclient.window = p->root; + e.xclient.format = 32; + e.xclient.data.l[0] = viewport.x; + e.xclient.data.l[1] = viewport.y; + e.xclient.data.l[2] = 0l; + e.xclient.data.l[3] = 0l; + e.xclient.data.l[4] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } +} + + +void NETRootInfo::setSupported() { + if (role != WindowManager) { +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::setSupported - role != WindowManager\n"); +#endif + + return; + } + + Atom atoms[netAtomCount]; + int pnum = 2; + + // Root window properties/messages + atoms[0] = net_supported; + atoms[1] = net_supporting_wm_check; + + if (p->properties[ PROTOCOLS ] & ClientList) + atoms[pnum++] = net_client_list; + + if (p->properties[ PROTOCOLS ] & ClientListStacking) + atoms[pnum++] = net_client_list_stacking; + + if (p->properties[ PROTOCOLS ] & NumberOfDesktops) + atoms[pnum++] = net_number_of_desktops; + + if (p->properties[ PROTOCOLS ] & DesktopGeometry) + atoms[pnum++] = net_desktop_geometry; + + if (p->properties[ PROTOCOLS ] & DesktopViewport) + atoms[pnum++] = net_desktop_viewport; + + if (p->properties[ PROTOCOLS ] & CurrentDesktop) + atoms[pnum++] = net_current_desktop; + + if (p->properties[ PROTOCOLS ] & DesktopNames) + atoms[pnum++] = net_desktop_names; + + if (p->properties[ PROTOCOLS ] & ActiveWindow) + atoms[pnum++] = net_active_window; + + if (p->properties[ PROTOCOLS ] & WorkArea) + atoms[pnum++] = net_workarea; + + if (p->properties[ PROTOCOLS ] & VirtualRoots) + atoms[pnum++] = net_virtual_roots; + + if (p->properties[ PROTOCOLS2 ] & WM2DesktopLayout) + atoms[pnum++] = net_desktop_layout; + + if (p->properties[ PROTOCOLS ] & CloseWindow) + atoms[pnum++] = net_close_window; + + if (p->properties[ PROTOCOLS2 ] & WM2RestackWindow) + atoms[pnum++] = net_restack_window; + + if (p->properties[ PROTOCOLS2 ] & WM2ShowingDesktop) + atoms[pnum++] = net_showing_desktop; + + // Application window properties/messages + if (p->properties[ PROTOCOLS ] & WMMoveResize) + atoms[pnum++] = net_wm_moveresize; + + if (p->properties[ PROTOCOLS2 ] & WM2MoveResizeWindow) + atoms[pnum++] = net_moveresize_window; + + if (p->properties[ PROTOCOLS ] & WMName) + atoms[pnum++] = net_wm_name; + + if (p->properties[ PROTOCOLS ] & WMVisibleName) + atoms[pnum++] = net_wm_visible_name; + + if (p->properties[ PROTOCOLS ] & WMIconName) + atoms[pnum++] = net_wm_icon_name; + + if (p->properties[ PROTOCOLS ] & WMVisibleIconName) + atoms[pnum++] = net_wm_visible_icon_name; + + if (p->properties[ PROTOCOLS ] & WMDesktop) + atoms[pnum++] = net_wm_desktop; + + if (p->properties[ PROTOCOLS ] & WMWindowType) { + atoms[pnum++] = net_wm_window_type; + + // Application window types + if (p->properties[ WINDOW_TYPES ] & NormalMask) + atoms[pnum++] = net_wm_window_type_normal; + if (p->properties[ WINDOW_TYPES ] & DesktopMask) + atoms[pnum++] = net_wm_window_type_desktop; + if (p->properties[ WINDOW_TYPES ] & DockMask) + atoms[pnum++] = net_wm_window_type_dock; + if (p->properties[ WINDOW_TYPES ] & ToolbarMask) + atoms[pnum++] = net_wm_window_type_toolbar; + if (p->properties[ WINDOW_TYPES ] & MenuMask) + atoms[pnum++] = net_wm_window_type_menu; + if (p->properties[ WINDOW_TYPES ] & DialogMask) + atoms[pnum++] = net_wm_window_type_dialog; + if (p->properties[ WINDOW_TYPES ] & UtilityMask) + atoms[pnum++] = net_wm_window_type_utility; + if (p->properties[ WINDOW_TYPES ] & SplashMask) + atoms[pnum++] = net_wm_window_type_splash; + if (p->properties[ WINDOW_TYPES ] & DropdownMenuMask) + atoms[pnum++] = net_wm_window_type_dropdown_menu; + if (p->properties[ WINDOW_TYPES ] & PopupMenuMask) + atoms[pnum++] = net_wm_window_type_popup_menu; + if (p->properties[ WINDOW_TYPES ] & TooltipMask) + atoms[pnum++] = net_wm_window_type_tooltip; + if (p->properties[ WINDOW_TYPES ] & NotificationMask) + atoms[pnum++] = net_wm_window_type_notification; + if (p->properties[ WINDOW_TYPES ] & ComboBoxMask) + atoms[pnum++] = net_wm_window_type_combobox; + if (p->properties[ WINDOW_TYPES ] & DNDIconMask) + atoms[pnum++] = net_wm_window_type_dnd; + // KDE extensions + if (p->properties[ WINDOW_TYPES ] & OverrideMask) + atoms[pnum++] = kde_net_wm_window_type_override; + if (p->properties[ WINDOW_TYPES ] & TopMenuMask) + atoms[pnum++] = kde_net_wm_window_type_topmenu; + } + + if (p->properties[ PROTOCOLS ] & WMState) { + atoms[pnum++] = net_wm_state; + + // Application window states + if (p->properties[ STATES ] & Modal) + atoms[pnum++] = net_wm_state_modal; + if (p->properties[ STATES ] & Sticky) + atoms[pnum++] = net_wm_state_sticky; + if (p->properties[ STATES ] & MaxVert) + atoms[pnum++] = net_wm_state_max_vert; + if (p->properties[ STATES ] & MaxHoriz) + atoms[pnum++] = net_wm_state_max_horiz; + if (p->properties[ STATES ] & Shaded) + atoms[pnum++] = net_wm_state_shaded; + if (p->properties[ STATES ] & SkipTaskbar) + atoms[pnum++] = net_wm_state_skip_taskbar; + if (p->properties[ STATES ] & SkipPager) + atoms[pnum++] = net_wm_state_skip_pager; + if (p->properties[ STATES ] & Hidden) + atoms[pnum++] = net_wm_state_hidden; + if (p->properties[ STATES ] & FullScreen) + atoms[pnum++] = net_wm_state_fullscreen; + if (p->properties[ STATES ] & KeepAbove) + atoms[pnum++] = net_wm_state_above; + if (p->properties[ STATES ] & KeepBelow) + atoms[pnum++] = net_wm_state_below; + if (p->properties[ STATES ] & DemandsAttention) + atoms[pnum++] = net_wm_state_demands_attention; + + if (p->properties[ STATES ] & StaysOnTop) + atoms[pnum++] = net_wm_state_stays_on_top; + } + + if (p->properties[ PROTOCOLS ] & WMStrut) + atoms[pnum++] = net_wm_strut; + + if (p->properties[ PROTOCOLS2 ] & WM2ExtendedStrut) + atoms[pnum++] = net_wm_extended_strut; + + if (p->properties[ PROTOCOLS ] & WMIconGeometry) + atoms[pnum++] = net_wm_icon_geometry; + + if (p->properties[ PROTOCOLS ] & WMIcon) + atoms[pnum++] = net_wm_icon; + + if (p->properties[ PROTOCOLS ] & WMPid) + atoms[pnum++] = net_wm_pid; + + if (p->properties[ PROTOCOLS ] & WMHandledIcons) + atoms[pnum++] = net_wm_handled_icons; + + if (p->properties[ PROTOCOLS ] & WMPing) + atoms[pnum++] = net_wm_ping; + + if (p->properties[ PROTOCOLS2 ] & WM2TakeActivity) + atoms[pnum++] = net_wm_take_activity; + + if (p->properties[ PROTOCOLS2 ] & WM2UserTime) + atoms[pnum++] = net_wm_user_time; + + if (p->properties[ PROTOCOLS2 ] & WM2StartupId) + atoms[pnum++] = net_startup_id; + + if (p->properties[ PROTOCOLS2 ] & WM2AllowedActions) { + atoms[pnum++] = net_wm_allowed_actions; + + // Actions + if (p->properties[ ACTIONS ] & ActionMove) + atoms[pnum++] = net_wm_action_move; + if (p->properties[ ACTIONS ] & ActionResize) + atoms[pnum++] = net_wm_action_resize; + if (p->properties[ ACTIONS ] & ActionMinimize) + atoms[pnum++] = net_wm_action_minimize; + if (p->properties[ ACTIONS ] & ActionShade) + atoms[pnum++] = net_wm_action_shade; + if (p->properties[ ACTIONS ] & ActionStick) + atoms[pnum++] = net_wm_action_stick; + if (p->properties[ ACTIONS ] & ActionMaxVert) + atoms[pnum++] = net_wm_action_max_vert; + if (p->properties[ ACTIONS ] & ActionMaxHoriz) + atoms[pnum++] = net_wm_action_max_horiz; + if (p->properties[ ACTIONS ] & ActionFullScreen) + atoms[pnum++] = net_wm_action_fullscreen; + if (p->properties[ ACTIONS ] & ActionChangeDesktop) + atoms[pnum++] = net_wm_action_change_desk; + if (p->properties[ ACTIONS ] & ActionClose) + atoms[pnum++] = net_wm_action_close; + } + + // KDE specific extensions + if (p->properties[ PROTOCOLS ] & KDESystemTrayWindows) + atoms[pnum++] = kde_net_system_tray_windows; + + if (p->properties[ PROTOCOLS ] & WMKDESystemTrayWinFor) + atoms[pnum++] = kde_net_wm_system_tray_window_for; + + if (p->properties[ PROTOCOLS ] & WMFrameExtents) { + atoms[pnum++] = net_frame_extents; + atoms[pnum++] = kde_net_wm_frame_strut; + } + + if (p->properties[ PROTOCOLS2 ] & WM2KDETemporaryRules) + atoms[pnum++] = kde_net_wm_temporary_rules; + + XChangeProperty(p->display, p->root, net_supported, XA_ATOM, 32, + PropModeReplace, (unsigned char *) atoms, pnum); + XChangeProperty(p->display, p->root, net_supporting_wm_check, XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &(p->supportwindow), 1); + +#ifdef NETWMDEBUG + fprintf(stderr, + "NETRootInfo::setSupported: _NET_SUPPORTING_WM_CHECK = 0x%lx on 0x%lx\n" + " : _NET_WM_NAME = '%s' on 0x%lx\n", + p->supportwindow, p->supportwindow, p->name, p->supportwindow); +#endif + + XChangeProperty(p->display, p->supportwindow, net_supporting_wm_check, + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(p->supportwindow), 1); + XChangeProperty(p->display, p->supportwindow, net_wm_name, UTF8_STRING, 8, + PropModeReplace, (unsigned char *) p->name, + strlen(p->name)); +} + +void NETRootInfo::updateSupportedProperties( Atom atom ) +{ + if( atom == net_supported ) + p->properties[ PROTOCOLS ] |= Supported; + + else if( atom == net_supporting_wm_check ) + p->properties[ PROTOCOLS ] |= SupportingWMCheck; + + else if( atom == net_client_list ) + p->properties[ PROTOCOLS ] |= ClientList; + + else if( atom == net_client_list_stacking ) + p->properties[ PROTOCOLS ] |= ClientListStacking; + + else if( atom == net_number_of_desktops ) + p->properties[ PROTOCOLS ] |= NumberOfDesktops; + + else if( atom == net_desktop_geometry ) + p->properties[ PROTOCOLS ] |= DesktopGeometry; + + else if( atom == net_desktop_viewport ) + p->properties[ PROTOCOLS ] |= DesktopViewport; + + else if( atom == net_current_desktop ) + p->properties[ PROTOCOLS ] |= CurrentDesktop; + + else if( atom == net_desktop_names ) + p->properties[ PROTOCOLS ] |= DesktopNames; + + else if( atom == net_active_window ) + p->properties[ PROTOCOLS ] |= ActiveWindow; + + else if( atom == net_workarea ) + p->properties[ PROTOCOLS ] |= WorkArea; + + else if( atom == net_virtual_roots ) + p->properties[ PROTOCOLS ] |= VirtualRoots; + + else if( atom == net_desktop_layout ) + p->properties[ PROTOCOLS2 ] |= WM2DesktopLayout; + + else if( atom == net_close_window ) + p->properties[ PROTOCOLS ] |= CloseWindow; + + else if( atom == net_restack_window ) + p->properties[ PROTOCOLS2 ] |= WM2RestackWindow; + + else if( atom == net_showing_desktop ) + p->properties[ PROTOCOLS2 ] |= WM2ShowingDesktop; + + // Application window properties/messages + else if( atom == net_wm_moveresize ) + p->properties[ PROTOCOLS ] |= WMMoveResize; + + else if( atom == net_moveresize_window ) + p->properties[ PROTOCOLS2 ] |= WM2MoveResizeWindow; + + else if( atom == net_wm_name ) + p->properties[ PROTOCOLS ] |= WMName; + + else if( atom == net_wm_visible_name ) + p->properties[ PROTOCOLS ] |= WMVisibleName; + + else if( atom == net_wm_icon_name ) + p->properties[ PROTOCOLS ] |= WMIconName; + + else if( atom == net_wm_visible_icon_name ) + p->properties[ PROTOCOLS ] |= WMVisibleIconName; + + else if( atom == net_wm_desktop ) + p->properties[ PROTOCOLS ] |= WMDesktop; + + else if( atom == net_wm_window_type ) + p->properties[ PROTOCOLS ] |= WMWindowType; + + // Application window types + else if( atom == net_wm_window_type_normal ) + p->properties[ WINDOW_TYPES ] |= NormalMask; + else if( atom == net_wm_window_type_desktop ) + p->properties[ WINDOW_TYPES ] |= DesktopMask; + else if( atom == net_wm_window_type_dock ) + p->properties[ WINDOW_TYPES ] |= DockMask; + else if( atom == net_wm_window_type_toolbar ) + p->properties[ WINDOW_TYPES ] |= ToolbarMask; + else if( atom == net_wm_window_type_menu ) + p->properties[ WINDOW_TYPES ] |= MenuMask; + else if( atom == net_wm_window_type_dialog ) + p->properties[ WINDOW_TYPES ] |= DialogMask; + else if( atom == net_wm_window_type_utility ) + p->properties[ WINDOW_TYPES ] |= UtilityMask; + else if( atom == net_wm_window_type_splash ) + p->properties[ WINDOW_TYPES ] |= SplashMask; + else if( atom == net_wm_window_type_dropdown_menu ) + p->properties[ WINDOW_TYPES ] |= DropdownMenuMask; + else if( atom == net_wm_window_type_popup_menu ) + p->properties[ WINDOW_TYPES ] |= PopupMenuMask; + else if( atom == net_wm_window_type_tooltip ) + p->properties[ WINDOW_TYPES ] |= TooltipMask; + else if( atom == net_wm_window_type_notification ) + p->properties[ WINDOW_TYPES ] |= NotificationMask; + else if( atom == net_wm_window_type_combobox ) + p->properties[ WINDOW_TYPES ] |= ComboBoxMask; + else if( atom == net_wm_window_type_dnd ) + p->properties[ WINDOW_TYPES ] |= DNDIconMask; + // KDE extensions + else if( atom == kde_net_wm_window_type_override ) + p->properties[ WINDOW_TYPES ] |= OverrideMask; + else if( atom == kde_net_wm_window_type_topmenu ) + p->properties[ WINDOW_TYPES ] |= TopMenuMask; + + else if( atom == net_wm_state ) + p->properties[ PROTOCOLS ] |= WMState; + + // Application window states + else if( atom == net_wm_state_modal ) + p->properties[ STATES ] |= Modal; + else if( atom == net_wm_state_sticky ) + p->properties[ STATES ] |= Sticky; + else if( atom == net_wm_state_max_vert ) + p->properties[ STATES ] |= MaxVert; + else if( atom == net_wm_state_max_horiz ) + p->properties[ STATES ] |= MaxHoriz; + else if( atom == net_wm_state_shaded ) + p->properties[ STATES ] |= Shaded; + else if( atom == net_wm_state_skip_taskbar ) + p->properties[ STATES ] |= SkipTaskbar; + else if( atom == net_wm_state_skip_pager ) + p->properties[ STATES ] |= SkipPager; + else if( atom == net_wm_state_hidden ) + p->properties[ STATES ] |= Hidden; + else if( atom == net_wm_state_fullscreen ) + p->properties[ STATES ] |= FullScreen; + else if( atom == net_wm_state_above ) + p->properties[ STATES ] |= KeepAbove; + else if( atom == net_wm_state_below ) + p->properties[ STATES ] |= KeepBelow; + else if( atom == net_wm_state_demands_attention ) + p->properties[ STATES ] |= DemandsAttention; + + else if( atom == net_wm_state_stays_on_top ) + p->properties[ STATES ] |= StaysOnTop; + + else if( atom == net_wm_strut ) + p->properties[ PROTOCOLS ] |= WMStrut; + + else if( atom == net_wm_extended_strut ) + p->properties[ PROTOCOLS2 ] |= WM2ExtendedStrut; + + else if( atom == net_wm_icon_geometry ) + p->properties[ PROTOCOLS ] |= WMIconGeometry; + + else if( atom == net_wm_icon ) + p->properties[ PROTOCOLS ] |= WMIcon; + + else if( atom == net_wm_pid ) + p->properties[ PROTOCOLS ] |= WMPid; + + else if( atom == net_wm_handled_icons ) + p->properties[ PROTOCOLS ] |= WMHandledIcons; + + else if( atom == net_wm_ping ) + p->properties[ PROTOCOLS ] |= WMPing; + + else if( atom == net_wm_take_activity ) + p->properties[ PROTOCOLS2 ] |= WM2TakeActivity; + + else if( atom == net_wm_user_time ) + p->properties[ PROTOCOLS2 ] |= WM2UserTime; + + else if( atom == net_startup_id ) + p->properties[ PROTOCOLS2 ] |= WM2StartupId; + + else if( atom == net_wm_allowed_actions ) + p->properties[ PROTOCOLS2 ] |= WM2AllowedActions; + + // Actions + else if( atom == net_wm_action_move ) + p->properties[ ACTIONS ] |= ActionMove; + else if( atom == net_wm_action_resize ) + p->properties[ ACTIONS ] |= ActionResize; + else if( atom == net_wm_action_minimize ) + p->properties[ ACTIONS ] |= ActionMinimize; + else if( atom == net_wm_action_shade ) + p->properties[ ACTIONS ] |= ActionShade; + else if( atom == net_wm_action_stick ) + p->properties[ ACTIONS ] |= ActionStick; + else if( atom == net_wm_action_max_vert ) + p->properties[ ACTIONS ] |= ActionMaxVert; + else if( atom == net_wm_action_max_horiz ) + p->properties[ ACTIONS ] |= ActionMaxHoriz; + else if( atom == net_wm_action_fullscreen ) + p->properties[ ACTIONS ] |= ActionFullScreen; + else if( atom == net_wm_action_change_desk ) + p->properties[ ACTIONS ] |= ActionChangeDesktop; + else if( atom == net_wm_action_close ) + p->properties[ ACTIONS ] |= ActionClose; + + // KDE specific extensions + else if( atom == kde_net_system_tray_windows ) + p->properties[ PROTOCOLS ] |= KDESystemTrayWindows; + + else if( atom == kde_net_wm_system_tray_window_for ) + p->properties[ PROTOCOLS ] |= WMKDESystemTrayWinFor; + + else if( atom == net_frame_extents ) + p->properties[ PROTOCOLS ] |= WMFrameExtents; + else if( atom == kde_net_wm_frame_strut ) + p->properties[ PROTOCOLS ] |= WMKDEFrameStrut; + + else if( atom == kde_net_wm_temporary_rules ) + p->properties[ PROTOCOLS2 ] |= WM2KDETemporaryRules; +} + +extern Time qt_x_user_time; +void NETRootInfo::setActiveWindow(Window window) { + setActiveWindow( window, FromUnknown, qt_x_user_time, None ); +} + +void NETRootInfo::setActiveWindow(Window window, NET::RequestSource src, + Time timestamp, Window active_window ) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::setActiveWindow(0x%lx) (%s)\n", + window, (role == WindowManager) ? "WM" : "Client"); +#endif + + if (role == WindowManager) { + p->active = window; + XChangeProperty(p->display, p->root, net_active_window, XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &(p->active), 1); + } else { + XEvent e; + + e.xclient.type = ClientMessage; + e.xclient.message_type = net_active_window; + e.xclient.display = p->display; + e.xclient.window = window; + e.xclient.format = 32; + e.xclient.data.l[0] = src; + e.xclient.data.l[1] = timestamp; + e.xclient.data.l[2] = active_window; + e.xclient.data.l[3] = 0l; + e.xclient.data.l[4] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } +} + + +void NETRootInfo::setWorkArea(int desktop, const NETRect &workarea) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::setWorkArea(%d, { %d, %d, %d, %d }) (%s)\n", + desktop, workarea.pos.x, workarea.pos.y, workarea.size.width, workarea.size.height, + (role == WindowManager) ? "WM" : "Client"); +#endif + + if (role != WindowManager || desktop < 1) return; + + p->workarea[desktop - 1] = workarea; + + long *wa = new long[p->number_of_desktops * 4]; + int i, o; + for (i = 0, o = 0; i < p->number_of_desktops; i++) { + wa[o++] = p->workarea[i].pos.x; + wa[o++] = p->workarea[i].pos.y; + wa[o++] = p->workarea[i].size.width; + wa[o++] = p->workarea[i].size.height; + } + + XChangeProperty(p->display, p->root, net_workarea, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) wa, + p->number_of_desktops * 4); + + delete [] wa; +} + + +void NETRootInfo::setVirtualRoots(Window *windows, unsigned int count) { + if (role != WindowManager) return; + + p->virtual_roots_count = count; + p->virtual_roots = windows; + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::setVirtualRoots: setting list with %ld windows\n", + p->virtual_roots_count); +#endif + + XChangeProperty(p->display, p->root, net_virtual_roots, XA_WINDOW, 32, + PropModeReplace, (unsigned char *) p->virtual_roots, + p->virtual_roots_count); +} + + +void NETRootInfo::setDesktopLayout(NET::Orientation orientation, int columns, int rows, + NET::DesktopLayoutCorner corner) +{ + p->desktop_layout_orientation = orientation; + p->desktop_layout_columns = columns; + p->desktop_layout_rows = rows; + p->desktop_layout_corner = corner; + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::setDesktopLayout: %d %d %d %d\n", + orientation, columns, rows, corner); +#endif + + long data[ 4 ]; + data[ 0 ] = orientation; + data[ 1 ] = columns; + data[ 2 ] = rows; + data[ 3 ] = corner; + XChangeProperty(p->display, p->root, net_desktop_layout, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) &data, 4); +} + + +void NETRootInfo::setShowingDesktop( bool showing ) { + if (role == WindowManager) { + long d = p->showing_desktop = showing; + XChangeProperty(p->display, p->root, net_showing_desktop, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) &d, 1); + } else { + XEvent e; + + e.xclient.type = ClientMessage; + e.xclient.message_type = net_showing_desktop; + e.xclient.display = p->display; + e.xclient.window = 0; + e.xclient.format = 32; + e.xclient.data.l[0] = showing ? 1 : 0; + e.xclient.data.l[1] = 0; + e.xclient.data.l[2] = 0; + e.xclient.data.l[3] = 0; + e.xclient.data.l[4] = 0; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } +} + + +bool NETRootInfo::showingDesktop() const { + return p->showing_desktop; +} + + +void NETRootInfo::closeWindowRequest(Window window) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::closeWindowRequest: requesting close for 0x%lx\n", + window); +#endif + + XEvent e; + + e.xclient.type = ClientMessage; + e.xclient.message_type = net_close_window; + e.xclient.display = p->display; + e.xclient.window = window; + e.xclient.format = 32; + e.xclient.data.l[0] = 0l; + e.xclient.data.l[1] = 0l; + e.xclient.data.l[2] = 0l; + e.xclient.data.l[3] = 0l; + e.xclient.data.l[4] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); +} + + +void NETRootInfo::moveResizeRequest(Window window, int x_root, int y_root, + Direction direction) +{ + +#ifdef NETWMDEBUG + fprintf(stderr, + "NETRootInfo::moveResizeRequest: requesting resize/move for 0x%lx (%d, %d, %d)\n", + window, x_root, y_root, direction); +#endif + + XEvent e; + + e.xclient.type = ClientMessage; + e.xclient.message_type = net_wm_moveresize; + e.xclient.display = p->display; + e.xclient.window = window, + e.xclient.format = 32; + e.xclient.data.l[0] = x_root; + e.xclient.data.l[1] = y_root; + e.xclient.data.l[2] = direction; + e.xclient.data.l[3] = 0l; + e.xclient.data.l[4] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); +} + +void NETRootInfo::moveResizeWindowRequest(Window window, int flags, int x, int y, int width, int height ) +{ + +#ifdef NETWMDEBUG + fprintf(stderr, + "NETRootInfo::moveResizeWindowRequest: resizing/moving 0x%lx (%d, %d, %d, %d, %d)\n", + window, flags, x, y, width, height); +#endif + + XEvent e; + + e.xclient.type = ClientMessage; + e.xclient.message_type = net_moveresize_window; + e.xclient.display = p->display; + e.xclient.window = window, + e.xclient.format = 32; + e.xclient.data.l[0] = flags; + e.xclient.data.l[1] = x; + e.xclient.data.l[2] = y; + e.xclient.data.l[3] = width; + e.xclient.data.l[4] = height; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); +} + +void NETRootInfo::restackRequest(Window window, Window above, int detail) +{ + restackRequest( window, FromTool, above, detail, qt_x_user_time ); +} + +void NETRootInfo::restackRequest(Window window, RequestSource src, Window above, int detail, Time timestamp ) +{ +#ifdef NETWMDEBUG + fprintf(stderr, + "NETRootInfo::restackRequest: requesting restack for 0x%lx (%lx, %d)\n", + window, above, detail); +#endif + + XEvent e; + + e.xclient.type = ClientMessage; + e.xclient.message_type = net_restack_window; + e.xclient.display = p->display; + e.xclient.window = window, + e.xclient.format = 32; + e.xclient.data.l[0] = src; + e.xclient.data.l[1] = above; + e.xclient.data.l[2] = detail; + e.xclient.data.l[3] = timestamp; + e.xclient.data.l[4] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); +} + +void NETRootInfo2::sendPing( Window window, Time timestamp ) +{ + if (role != WindowManager) return; +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo2::setPing: window 0x%lx, timestamp %lu\n", + window, timestamp ); +#endif + XEvent e; + e.xclient.type = ClientMessage; + e.xclient.message_type = wm_protocols; + e.xclient.display = p->display; + e.xclient.window = window, + e.xclient.format = 32; + e.xclient.data.l[0] = net_wm_ping; + e.xclient.data.l[1] = timestamp; + e.xclient.data.l[2] = window; + e.xclient.data.l[3] = 0; + e.xclient.data.l[4] = 0; + + XSendEvent(p->display, window, False, 0, &e); +} + +void NETRootInfo3::takeActivity( Window window, Time timestamp, long flags ) +{ + if (role != WindowManager) return; +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo2::takeActivity: window 0x%lx, timestamp %lu, flags 0x%lx\n", + window, timestamp, flags ); +#endif + XEvent e; + e.xclient.type = ClientMessage; + e.xclient.message_type = wm_protocols; + e.xclient.display = p->display; + e.xclient.window = window, + e.xclient.format = 32; + e.xclient.data.l[0] = net_wm_take_activity; + e.xclient.data.l[1] = timestamp; + e.xclient.data.l[2] = window; + e.xclient.data.l[3] = flags; + e.xclient.data.l[4] = 0; + + XSendEvent(p->display, window, False, 0, &e); +} + + + +// assignment operator + +const NETRootInfo &NETRootInfo::operator=(const NETRootInfo &rootinfo) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::operator=()\n"); +#endif + + if (p != rootinfo.p) { + refdec_nri(p); + + if (! p->ref) delete p; + } + + p = rootinfo.p; + role = rootinfo.role; + p->ref++; + + return *this; +} + +unsigned long NETRootInfo::event(XEvent *ev ) +{ + unsigned long props[ 1 ]; + event( ev, props, 1 ); + return props[ 0 ]; +} + +void NETRootInfo::event(XEvent *event, unsigned long* properties, int properties_size ) +{ + unsigned long props[ PROPERTIES_SIZE ] = { 0, 0, 0, 0, 0 }; + assert( PROPERTIES_SIZE == 5 ); // add elements above + unsigned long& dirty = props[ PROTOCOLS ]; + unsigned long& dirty2 = props[ PROTOCOLS2 ]; + bool do_update = false; + + // the window manager will be interested in client messages... no other + // client should get these messages + if (role == WindowManager && event->type == ClientMessage && + event->xclient.format == 32) { +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::event: handling ClientMessage event\n"); +#endif + + if (event->xclient.message_type == net_number_of_desktops) { + dirty = NumberOfDesktops; + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::event: changeNumberOfDesktops(%ld)\n", + event->xclient.data.l[0]); +#endif + + changeNumberOfDesktops(event->xclient.data.l[0]); + } else if (event->xclient.message_type == net_desktop_geometry) { + dirty = DesktopGeometry; + + NETSize sz; + sz.width = event->xclient.data.l[0]; + sz.height = event->xclient.data.l[1]; + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::event: changeDesktopGeometry( -- , { %d, %d })\n", + sz.width, sz.height); +#endif + + changeDesktopGeometry(~0, sz); + } else if (event->xclient.message_type == net_desktop_viewport) { + dirty = DesktopViewport; + + NETPoint pt; + pt.x = event->xclient.data.l[0]; + pt.y = event->xclient.data.l[1]; + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::event: changeDesktopViewport(%d, { %d, %d })\n", + p->current_desktop, pt.x, pt.y); +#endif + + changeDesktopViewport(p->current_desktop, pt); + } else if (event->xclient.message_type == net_current_desktop) { + dirty = CurrentDesktop; + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::event: changeCurrentDesktop(%ld)\n", + event->xclient.data.l[0] + 1); +#endif + + changeCurrentDesktop(event->xclient.data.l[0] + 1); + } else if (event->xclient.message_type == net_active_window) { + dirty = ActiveWindow; + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::event: changeActiveWindow(0x%lx)\n", + event->xclient.window); +#endif + + changeActiveWindow(event->xclient.window); + if( NETRootInfo2* this2 = dynamic_cast< NETRootInfo2* >( this )) + { + RequestSource src = FromUnknown; + Time timestamp = CurrentTime; + Window active_window = None; + // make sure there aren't unknown values + if( event->xclient.data.l[0] >= FromUnknown + && event->xclient.data.l[0] <= FromTool ) + { + src = static_cast< RequestSource >( event->xclient.data.l[0] ); + timestamp = event->xclient.data.l[1]; + active_window = event->xclient.data.l[2]; + } + this2->changeActiveWindow( event->xclient.window, src, timestamp, active_window ); + } + } else if (event->xclient.message_type == net_wm_moveresize) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::event: moveResize(%ld, %ld, %ld, %ld)\n", + event->xclient.window, + event->xclient.data.l[0], + event->xclient.data.l[1], + event->xclient.data.l[2] + ); +#endif + + moveResize(event->xclient.window, + event->xclient.data.l[0], + event->xclient.data.l[1], + event->xclient.data.l[2]); + } else if (event->xclient.message_type == net_moveresize_window) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::event: moveResizeWindow(%ld, %ld, %ld, %ld, %ld, %ld)\n", + event->xclient.window, + event->xclient.data.l[0], + event->xclient.data.l[1], + event->xclient.data.l[2], + event->xclient.data.l[3], + event->xclient.data.l[4] + ); +#endif + + if( NETRootInfo2* this2 = dynamic_cast< NETRootInfo2* >( this )) + this2->moveResizeWindow(event->xclient.window, + event->xclient.data.l[0], + event->xclient.data.l[1], + event->xclient.data.l[2], + event->xclient.data.l[3], + event->xclient.data.l[4]); + } else if (event->xclient.message_type == net_close_window) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::event: closeWindow(0x%lx)\n", + event->xclient.window); +#endif + + closeWindow(event->xclient.window); + } else if (event->xclient.message_type == net_restack_window) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::event: restackWindow(0x%lx)\n", + event->xclient.window); +#endif + + if( NETRootInfo3* this3 = dynamic_cast< NETRootInfo3* >( this )) + { + RequestSource src = FromUnknown; + Time timestamp = CurrentTime; + // make sure there aren't unknown values + if( event->xclient.data.l[0] >= FromUnknown + && event->xclient.data.l[0] <= FromTool ) + { + src = static_cast< RequestSource >( event->xclient.data.l[0] ); + timestamp = event->xclient.data.l[3]; + } + this3->restackWindow(event->xclient.window, src, + event->xclient.data.l[1], event->xclient.data.l[2], timestamp); + } + else if( NETRootInfo2* this2 = dynamic_cast< NETRootInfo2* >( this )) + this2->restackWindow(event->xclient.window, + event->xclient.data.l[1], event->xclient.data.l[2]); + } else if (event->xclient.message_type == wm_protocols + && (Atom)event->xclient.data.l[ 0 ] == net_wm_ping) { + dirty = WMPing; + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo2::event: gotPing(0x%lx,%lu)\n", + event->xclient.window, event->xclient.data.l[1]); +#endif + if( NETRootInfo2* this2 = dynamic_cast< NETRootInfo2* >( this )) + this2->gotPing( event->xclient.data.l[2], event->xclient.data.l[1]); + } else if (event->xclient.message_type == wm_protocols + && (Atom)event->xclient.data.l[ 0 ] == net_wm_take_activity) { + dirty2 = WM2TakeActivity; + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo2::event: gotTakeActivity(0x%lx,%lu,0x%lx)\n", + event->xclient.window, event->xclient.data.l[1], event->xclient.data.l[3]); +#endif + if( NETRootInfo3* this3 = dynamic_cast< NETRootInfo3* >( this )) + this3->gotTakeActivity( event->xclient.data.l[2], event->xclient.data.l[1], + event->xclient.data.l[3]); + } else if (event->xclient.message_type == net_showing_desktop) { + dirty2 = WM2ShowingDesktop; + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::event: changeShowingDesktop(%ld)\n", + event->xclient.data.l[0]); +#endif + + if( NETRootInfo4* this4 = dynamic_cast< NETRootInfo4* >( this )) + this4->changeShowingDesktop(event->xclient.data.l[0]); + } + } + + if (event->type == PropertyNotify) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::event: handling PropertyNotify event\n"); +#endif + + XEvent pe = *event; + + Bool done = False; + Bool compaction = False; + while (! done) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::event: loop fire\n"); +#endif + + if (pe.xproperty.atom == net_client_list) + dirty |= ClientList; + else if (pe.xproperty.atom == net_client_list_stacking) + dirty |= ClientListStacking; + else if (pe.xproperty.atom == kde_net_system_tray_windows) + dirty |= KDESystemTrayWindows; + else if (pe.xproperty.atom == net_desktop_names) + dirty |= DesktopNames; + else if (pe.xproperty.atom == net_workarea) + dirty |= WorkArea; + else if (pe.xproperty.atom == net_number_of_desktops) + dirty |= NumberOfDesktops; + else if (pe.xproperty.atom == net_desktop_geometry) + dirty |= DesktopGeometry; + else if (pe.xproperty.atom == net_desktop_viewport) + dirty |= DesktopViewport; + else if (pe.xproperty.atom == net_current_desktop) + dirty |= CurrentDesktop; + else if (pe.xproperty.atom == net_active_window) + dirty |= ActiveWindow; + else if (pe.xproperty.atom == net_showing_desktop) + dirty2 |= WM2ShowingDesktop; +// else if (pe.xproperty.atom == net_supported ) +// dirty |= Supported; // update here? + else if (pe.xproperty.atom == net_supporting_wm_check ) + dirty |= SupportingWMCheck; + else if (pe.xproperty.atom == net_virtual_roots ) + dirty |= VirtualRoots; + else if (pe.xproperty.atom == net_desktop_layout ) + dirty2 |= WM2DesktopLayout; + else { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::event: putting back event and breaking\n"); +#endif + + if ( compaction ) + XPutBackEvent(p->display, &pe); + break; + } + + if (XCheckTypedWindowEvent(p->display, p->root, PropertyNotify, &pe) ) + compaction = True; + else + break; + } + + do_update = true; + } + + if( do_update ) + update( props ); + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::event: handled events, returning dirty = 0x%lx, 0x%lx\n", + dirty, dirty2); +#endif + + if( properties_size > PROPERTIES_SIZE ) + properties_size = PROPERTIES_SIZE; + for( int i = 0; + i < properties_size; + ++i ) + properties[ i ] = props[ i ]; +} + + +// private functions to update the data we keep + +void NETRootInfo::update( const unsigned long dirty_props[] ) +{ + Atom type_ret; + int format_ret; + unsigned char *data_ret; + unsigned long nitems_ret, unused; + unsigned long props[ PROPERTIES_SIZE ]; + for( int i = 0; + i < PROPERTIES_SIZE; + ++i ) + props[ i ] = dirty_props[ i ] & p->client_properties[ i ]; + const unsigned long& dirty = props[ PROTOCOLS ]; + const unsigned long& dirty2 = props[ PROTOCOLS2 ]; + + if (dirty & Supported ) { + // only in Client mode + for( int i = 0; i < PROPERTIES_SIZE; ++i ) + p->properties[ i ] = 0; + if( XGetWindowProperty(p->display, p->root, net_supported, + 0l, MAX_PROP_SIZE, False, XA_ATOM, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success ) { + if( type_ret == XA_ATOM && format_ret == 32 ) { + Atom* atoms = (Atom*) data_ret; + for( unsigned int i = 0; + i < nitems_ret; + ++i ) + updateSupportedProperties( atoms[ i ] ); + } + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & ClientList) { + bool read_ok = false; + if (XGetWindowProperty(p->display, p->root, net_client_list, + 0l, MAX_PROP_SIZE, False, XA_WINDOW, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_WINDOW && format_ret == 32) { + Window *wins = (Window *) data_ret; + + qsort(wins, nitems_ret, sizeof(Window), wcmp); + + if (p->clients) { + if (role == Client) { + unsigned long new_index = 0, old_index = 0; + unsigned long new_count = nitems_ret, + old_count = p->clients_count; + + while (old_index < old_count || new_index < new_count) { + if (old_index == old_count) { + addClient(wins[new_index++]); + } else if (new_index == new_count) { + removeClient(p->clients[old_index++]); + } else { + if (p->clients[old_index] < + wins[new_index]) { + removeClient(p->clients[old_index++]); + } else if (wins[new_index] < + p->clients[old_index]) { + addClient(wins[new_index++]); + } else { + new_index++; + old_index++; + } + } + } + } + + delete [] p->clients; + } else { +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::update: client list null, creating\n"); +#endif + + unsigned long n; + for (n = 0; n < nitems_ret; n++) { + addClient(wins[n]); + } + } + + p->clients_count = nitems_ret; + p->clients = nwindup(wins, p->clients_count); + read_ok = true; + } + + if ( data_ret ) + XFree(data_ret); + } + if( !read_ok ) { + for( unsigned int i = 0; i < p->clients_count; ++ i ) + removeClient(p->clients[i]); + p->clients_count = 0; + delete[] p->clients; + p->clients = NULL; + } + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::update: client list updated (%ld clients)\n", + p->clients_count); +#endif + } + + if (dirty & KDESystemTrayWindows) { + bool read_ok = false; + if (XGetWindowProperty(p->display, p->root, kde_net_system_tray_windows, + 0l, MAX_PROP_SIZE, False, XA_WINDOW, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_WINDOW && format_ret == 32) { + Window *wins = (Window *) data_ret; + + qsort(wins, nitems_ret, sizeof(Window), wcmp); + + if (p->kde_system_tray_windows) { + if (role == Client) { + unsigned long new_index = 0, new_count = nitems_ret; + unsigned long old_index = 0, + old_count = p->kde_system_tray_windows_count; + + while(old_index < old_count || new_index < new_count) { + if (old_index == old_count) { + addSystemTrayWin(wins[new_index++]); + } else if (new_index == new_count) { + removeSystemTrayWin(p->kde_system_tray_windows[old_index++]); + } else { + if (p->kde_system_tray_windows[old_index] < + wins[new_index]) { + removeSystemTrayWin(p->kde_system_tray_windows[old_index++]); + } else if (wins[new_index] < + p->kde_system_tray_windows[old_index]) { + addSystemTrayWin(wins[new_index++]); + } else { + new_index++; + old_index++; + } + } + } + } + + } else { + unsigned long n; + for (n = 0; n < nitems_ret; n++) { + addSystemTrayWin(wins[n]); + } + } + + p->kde_system_tray_windows_count = nitems_ret; + delete [] p->kde_system_tray_windows; + p->kde_system_tray_windows = + nwindup(wins, p->kde_system_tray_windows_count); + read_ok = true; + } + + if ( data_ret ) + XFree(data_ret); + } + if( !read_ok ) { + for( unsigned int i = 0; i < p->kde_system_tray_windows_count; ++i ) + removeSystemTrayWin(p->kde_system_tray_windows[i]); + p->kde_system_tray_windows_count = 0; + delete [] p->kde_system_tray_windows; + p->kde_system_tray_windows = NULL; + } + } + + if (dirty & ClientListStacking) { + p->stacking_count = 0; + delete[] p->stacking; + p->stacking = NULL; + if (XGetWindowProperty(p->display, p->root, net_client_list_stacking, + 0, MAX_PROP_SIZE, False, XA_WINDOW, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_WINDOW && format_ret == 32) { + Window *wins = (Window *) data_ret; + + p->stacking_count = nitems_ret; + p->stacking = nwindup(wins, p->stacking_count); + } + +#ifdef NETWMDEBUG + fprintf(stderr,"NETRootInfo::update: client stacking updated (%ld clients)\n", + p->stacking_count); +#endif + + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & NumberOfDesktops) { + p->number_of_desktops = 0; + + if (XGetWindowProperty(p->display, p->root, net_number_of_desktops, + 0l, 1l, False, XA_CARDINAL, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 1) { + p->number_of_desktops = *((long *) data_ret); + } + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::update: number of desktops = %d\n", + p->number_of_desktops); +#endif + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & DesktopGeometry) { + p->geometry = p->rootSize; + if (XGetWindowProperty(p->display, p->root, net_desktop_geometry, + 0l, 2l, False, XA_CARDINAL, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_CARDINAL && format_ret == 32 && + nitems_ret == 2) { + long *data = (long *) data_ret; + + p->geometry.width = data[0]; + p->geometry.height = data[1]; + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::update: desktop geometry updated\n"); +#endif + } + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & DesktopViewport) { + for (int i = 0; i < p->viewport.size(); i++) + p->viewport[i].x = p->viewport[i].y = 0; + if (XGetWindowProperty(p->display, p->root, net_desktop_viewport, + 0l, 2l, False, XA_CARDINAL, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_CARDINAL && format_ret == 32 && + nitems_ret == 2) { + long *data = (long *) data_ret; + + int d, i, n; + n = nitems_ret / 2; + for (d = 0, i = 0; d < n; d++) { + p->viewport[d].x = data[i++]; + p->viewport[d].y = data[i++]; + } + +#ifdef NETWMDEBUG + fprintf(stderr, + "NETRootInfo::update: desktop viewport array updated (%d entries)\n", + p->viewport.size()); + + if (nitems_ret % 2 != 0) { + fprintf(stderr, + "NETRootInfo::update(): desktop viewport array " + "size not a multiple of 2\n"); + } +#endif + } + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & CurrentDesktop) { + p->current_desktop = 0; + if (XGetWindowProperty(p->display, p->root, net_current_desktop, + 0l, 1l, False, XA_CARDINAL, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 1) { + p->current_desktop = *((long *) data_ret) + 1; + } + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::update: current desktop = %d\n", + p->current_desktop); +#endif + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & DesktopNames) { + for( int i = 0; i < p->desktop_names.size(); ++i ) + delete[] p->desktop_names[ i ]; + p->desktop_names.reset(); + if (XGetWindowProperty(p->display, p->root, net_desktop_names, + 0l, MAX_PROP_SIZE, False, UTF8_STRING, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == UTF8_STRING && format_ret == 8) { + const char *d = (const char *) data_ret; + unsigned int s, n, index; + + for (s = 0, n = 0, index = 0; n < nitems_ret; n++) { + if (d[n] == '\0') { + delete [] p->desktop_names[index]; + p->desktop_names[index++] = nstrndup((d + s), n - s + 1); + s = n + 1; + } + } + } + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::update: desktop names array updated (%d entries)\n", + p->desktop_names.size()); +#endif + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & ActiveWindow) { + p->active = None; + if (XGetWindowProperty(p->display, p->root, net_active_window, 0l, 1l, + False, XA_WINDOW, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_WINDOW && format_ret == 32 && nitems_ret == 1) { + p->active = *((Window *) data_ret); + } + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::update: active window = 0x%lx\n", + p->active); +#endif + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & WorkArea) { + p->workarea.reset(); + if (XGetWindowProperty(p->display, p->root, net_workarea, 0l, + (p->number_of_desktops * 4), False, XA_CARDINAL, + &type_ret, &format_ret, &nitems_ret, &unused, + &data_ret) + == Success) { + if (type_ret == XA_CARDINAL && format_ret == 32 && + nitems_ret == (unsigned) (p->number_of_desktops * 4)) { + long *d = (long *) data_ret; + int i, j; + for (i = 0, j = 0; i < p->number_of_desktops; i++) { + p->workarea[i].pos.x = d[j++]; + p->workarea[i].pos.y = d[j++]; + p->workarea[i].size.width = d[j++]; + p->workarea[i].size.height = d[j++]; + } + } + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::update: work area array updated (%d entries)\n", + p->workarea.size()); +#endif + if ( data_ret ) + XFree(data_ret); + } + } + + + if (dirty & SupportingWMCheck) { + p->supportwindow = None; + delete[] p->name; + p->name = NULL; + if (XGetWindowProperty(p->display, p->root, net_supporting_wm_check, + 0l, 1l, False, XA_WINDOW, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_WINDOW && format_ret == 32 && nitems_ret == 1) { + p->supportwindow = *((Window *) data_ret); + + unsigned char *name_ret; + if (XGetWindowProperty(p->display, p->supportwindow, + net_wm_name, 0l, MAX_PROP_SIZE, False, + UTF8_STRING, &type_ret, &format_ret, + &nitems_ret, &unused, &name_ret) + == Success) { + if (type_ret == UTF8_STRING && format_ret == 8) + p->name = nstrndup((const char *) name_ret, nitems_ret); + + if ( name_ret ) + XFree(name_ret); + } + } + +#ifdef NETWMDEBUG + fprintf(stderr, + "NETRootInfo::update: supporting window manager = '%s'\n", + p->name); +#endif + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & VirtualRoots) { + p->virtual_roots_count = 0; + delete[] p->virtual_roots; + p->virtual_roots = NULL; + if (XGetWindowProperty(p->display, p->root, net_virtual_roots, + 0, MAX_PROP_SIZE, False, XA_WINDOW, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_WINDOW && format_ret == 32) { + Window *wins = (Window *) data_ret; + + p->virtual_roots_count = nitems_ret; + p->virtual_roots = nwindup(wins, p->virtual_roots_count); + } + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::updated: virtual roots updated (%ld windows)\n", + p->virtual_roots_count); +#endif + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty2 & WM2DesktopLayout) { + p->desktop_layout_orientation = OrientationHorizontal; + p->desktop_layout_corner = DesktopLayoutCornerTopLeft; + p->desktop_layout_columns = p->desktop_layout_rows = 0; + if (XGetWindowProperty(p->display, p->root, net_desktop_layout, + 0, MAX_PROP_SIZE, False, XA_CARDINAL, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_CARDINAL && format_ret == 32) { + long* data = (long*) data_ret; + if( nitems_ret >= 4 && data[ 3 ] >= 0 && data[ 3 ] <= 3 ) + p->desktop_layout_corner = (NET::DesktopLayoutCorner)data[ 3 ]; + if( nitems_ret >= 3 ) { + if( data[ 0 ] >= 0 && data[ 0 ] <= 1 ) + p->desktop_layout_orientation = (NET::Orientation)data[ 0 ]; + p->desktop_layout_columns = data[ 1 ]; + p->desktop_layout_rows = data[ 2 ]; + } + } + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::updated: desktop layout updated (%d %d %d %d)\n", + p->desktop_layout_orientation, p->desktop_layout_columns, + p->desktop_layout_rows, p->desktop_layout_corner ); +#endif + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty2 & WM2ShowingDesktop) { + p->showing_desktop = false; + if (XGetWindowProperty(p->display, p->root, net_showing_desktop, + 0, MAX_PROP_SIZE, False, XA_CARDINAL, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 1) { + p->showing_desktop = *((long *) data_ret); + } + +#ifdef NETWMDEBUG + fprintf(stderr, "NETRootInfo::update: showing desktop = %d\n", + p->showing_desktop); +#endif + if ( data_ret ) + XFree(data_ret); + } + } +} + + +Display *NETRootInfo::x11Display() const { + return p->display; +} + + +Window NETRootInfo::rootWindow() const { + return p->root; +} + + +Window NETRootInfo::supportWindow() const { + return p->supportwindow; +} + + +const char *NETRootInfo::wmName() const { + return p->name; } + + +int NETRootInfo::screenNumber() const { + return p->screen; +} + + +unsigned long NETRootInfo::supported() const { + return role == WindowManager + ? p->properties[ PROTOCOLS ] + : p->client_properties[ PROTOCOLS ]; +} + +const unsigned long* NETRootInfo::supportedProperties() const { + return p->properties; +} + +const unsigned long* NETRootInfo::passedProperties() const { + return role == WindowManager + ? p->properties + : p->client_properties; +} + +bool NETRootInfo::isSupported( NET::Property property ) const { + return p->properties[ PROTOCOLS ] & property; +} + +bool NETRootInfo::isSupported( NET::Property2 property ) const { + return p->properties[ PROTOCOLS2 ] & property; +} + +bool NETRootInfo::isSupported( NET::WindowType type ) const { + return p->properties[ WINDOW_TYPES ] & type; +} + +bool NETRootInfo::isSupported( NET::State state ) const { + return p->properties[ STATES ] & state; +} + +bool NETRootInfo::isSupported( NET::Action action ) const { + return p->properties[ ACTIONS ] & action; +} + +const Window *NETRootInfo::clientList() const { + return p->clients; +} + + +int NETRootInfo::clientListCount() const { + return p->clients_count; +} + + +const Window *NETRootInfo::clientListStacking() const { + return p->stacking; +} + + +int NETRootInfo::clientListStackingCount() const { + return p->stacking_count; +} + + +const Window *NETRootInfo::kdeSystemTrayWindows() const { + return p->kde_system_tray_windows; +} + + +int NETRootInfo::kdeSystemTrayWindowsCount() const { + return p->kde_system_tray_windows_count; +} + + +NETSize NETRootInfo::desktopGeometry(int) const { + return p->geometry.width != 0 ? p->geometry : p->rootSize; +} + + +NETPoint NETRootInfo::desktopViewport(int desktop) const { + if (desktop < 1) { + NETPoint pt; // set to (0,0) + return pt; + } + + return p->viewport[desktop - 1]; +} + + +NETRect NETRootInfo::workArea(int desktop) const { + if (desktop < 1) { + NETRect rt; + return rt; + } + + return p->workarea[desktop - 1]; +} + + +const char *NETRootInfo::desktopName(int desktop) const { + if (desktop < 1) { + return 0; + } + + return p->desktop_names[desktop - 1]; +} + + +const Window *NETRootInfo::virtualRoots( ) const { + return p->virtual_roots; +} + + +int NETRootInfo::virtualRootsCount() const { + return p->virtual_roots_count; +} + + +NET::Orientation NETRootInfo::desktopLayoutOrientation() const { + return p->desktop_layout_orientation; +} + + +QSize NETRootInfo::desktopLayoutColumnsRows() const { + return QSize( p->desktop_layout_columns, p->desktop_layout_rows ); +} + + +NET::DesktopLayoutCorner NETRootInfo::desktopLayoutCorner() const { + return p->desktop_layout_corner; +} + + +int NETRootInfo::numberOfDesktops() const { + return p->number_of_desktops == 0 ? 1 : p->number_of_desktops; +} + + +int NETRootInfo::currentDesktop() const { + return p->current_desktop == 0 ? 1 : p->current_desktop; +} + + +Window NETRootInfo::activeWindow() const { + return p->active; +} + + +// NETWinInfo stuffs + +const int NETWinInfo::OnAllDesktops = NET::OnAllDesktops; + +NETWinInfo::NETWinInfo(Display *display, Window window, Window rootWindow, + const unsigned long properties[], int properties_size, + Role role) +{ + +#ifdef NETWMDEBUG + fprintf(stderr, "NETWinInfo::NETWinInfo: constructing object with role '%s'\n", + (role == WindowManager) ? "WindowManager" : "Client"); +#endif + + p = new NETWinInfoPrivate; + p->ref = 1; + + p->display = display; + p->window = window; + p->root = rootWindow; + p->mapping_state = Withdrawn; + p->mapping_state_dirty = True; + p->state = 0; + p->types[ 0 ] = Unknown; + p->name = (char *) 0; + p->visible_name = (char *) 0; + p->icon_name = (char *) 0; + p->visible_icon_name = (char *) 0; + p->desktop = p->pid = p->handled_icons = 0; + p->user_time = -1U; + p->startup_id = NULL; + p->transient_for = None; + p->window_group = None; + p->allowed_actions = 0; + p->has_net_support = false; + p->class_class = (char*) 0; + p->class_name = (char*) 0; + p->role = (char*) 0; + p->client_machine = (char*) 0; + + // p->strut.left = p->strut.right = p->strut.top = p->strut.bottom = 0; + // p->frame_strut.left = p->frame_strut.right = p->frame_strut.top = + // p->frame_strut.bottom = 0; + + p->kde_system_tray_win_for = 0; + + for( int i = 0; + i < PROPERTIES_SIZE; + ++i ) + p->properties[ i ] = 0; + if( properties_size > PROPERTIES_SIZE ) + properties_size = PROPERTIES_SIZE; + for( int i = 0; + i < properties_size; + ++i ) + p->properties[ i ] = properties[ i ]; + + p->icon_count = 0; + + this->role = role; + + if (! netwm_atoms_created) create_atoms(p->display); + + update(p->properties); +} + + +NETWinInfo::NETWinInfo(Display *display, Window window, Window rootWindow, + unsigned long properties, Role role) +{ + +#ifdef NETWMDEBUG + fprintf(stderr, "NETWinInfo::NETWinInfo: constructing object with role '%s'\n", + (role == WindowManager) ? "WindowManager" : "Client"); +#endif + + p = new NETWinInfoPrivate; + p->ref = 1; + + p->display = display; + p->window = window; + p->root = rootWindow; + p->mapping_state = Withdrawn; + p->mapping_state_dirty = True; + p->state = 0; + p->types[ 0 ] = Unknown; + p->name = (char *) 0; + p->visible_name = (char *) 0; + p->icon_name = (char *) 0; + p->visible_icon_name = (char *) 0; + p->desktop = p->pid = p->handled_icons = 0; + p->user_time = -1U; + p->startup_id = NULL; + p->transient_for = None; + p->window_group = None; + p->allowed_actions = 0; + p->has_net_support = false; + p->class_class = (char*) 0; + p->class_name = (char*) 0; + p->role = (char*) 0; + p->client_machine = (char*) 0; + + // p->strut.left = p->strut.right = p->strut.top = p->strut.bottom = 0; + // p->frame_strut.left = p->frame_strut.right = p->frame_strut.top = + // p->frame_strut.bottom = 0; + + p->kde_system_tray_win_for = 0; + + for( int i = 0; + i < PROPERTIES_SIZE; + ++i ) + p->properties[ i ] = 0; + p->properties[ PROTOCOLS ] = properties; + + p->icon_count = 0; + + this->role = role; + + if (! netwm_atoms_created) create_atoms(p->display); + + update(p->properties); +} + + +NETWinInfo::NETWinInfo(const NETWinInfo &wininfo) { + p = wininfo.p; + p->ref++; +} + + +NETWinInfo::~NETWinInfo() { + refdec_nwi(p); + + if (! p->ref) delete p; +} + + +// assignment operator + +const NETWinInfo &NETWinInfo::operator=(const NETWinInfo &wininfo) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETWinInfo::operator=()\n"); +#endif + + if (p != wininfo.p) { + refdec_nwi(p); + + if (! p->ref) delete p; + } + + p = wininfo.p; + role = wininfo.role; + p->ref++; + + return *this; +} + + +void NETWinInfo::setIcon(NETIcon icon, Bool replace) { + setIconInternal( p->icons, p->icon_count, net_wm_icon, icon, replace ); +} + +void NETWinInfo::setIconInternal(NETRArray<NETIcon>& icons, int& icon_count, Atom property, NETIcon icon, Bool replace) { + if (role != Client) return; + + int proplen, i, sz, j; + + if (replace) { + + for (i = 0; i < icons.size(); i++) { + delete [] icons[i].data; + icons[i].data = 0; + icons[i].size.width = 0; + icons[i].size.height = 0; + } + + icon_count = 0; + } + + // assign icon + icons[icon_count] = icon; + icon_count++; + + // do a deep copy, we want to own the data + NETIcon &ni = icons[icon_count - 1]; + sz = ni.size.width * ni.size.height; + CARD32 *d = new CARD32[sz]; + ni.data = (unsigned char *) d; + memcpy(d, icon.data, sz * sizeof(CARD32)); + + // compute property length + for (i = 0, proplen = 0; i < icon_count; i++) { + proplen += 2 + (icons[i].size.width * + icons[i].size.height); + } + + CARD32 *d32; + long *prop = new long[proplen], *pprop = prop; + for (i = 0; i < icon_count; i++) { + // copy size into property + *pprop++ = icons[i].size.width; + *pprop++ = icons[i].size.height; + + // copy data into property + sz = (icons[i].size.width * icons[i].size.height); + d32 = (CARD32 *) icons[i].data; + for (j = 0; j < sz; j++) *pprop++ = *d32++; + } + + XChangeProperty(p->display, p->window, property, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) prop, proplen); + + delete [] prop; +} + + +void NETWinInfo::setIconGeometry(NETRect geometry) { + if (role != Client) return; + + p->icon_geom = geometry; + + if( geometry.size.width == 0 ) // empty + XDeleteProperty(p->display, p->window, net_wm_icon_geometry); + else { + long data[4]; + data[0] = geometry.pos.x; + data[1] = geometry.pos.y; + data[2] = geometry.size.width; + data[3] = geometry.size.height; + + XChangeProperty(p->display, p->window, net_wm_icon_geometry, XA_CARDINAL, + 32, PropModeReplace, (unsigned char *) data, 4); + } +} + + +void NETWinInfo::setExtendedStrut(const NETExtendedStrut& extended_strut ) { + if (role != Client) return; + + p->extended_strut = extended_strut; + + long data[12]; + data[0] = extended_strut.left_width; + data[1] = extended_strut.right_width; + data[2] = extended_strut.top_width; + data[3] = extended_strut.bottom_width; + data[4] = extended_strut.left_start; + data[5] = extended_strut.left_end; + data[6] = extended_strut.right_start; + data[7] = extended_strut.right_end; + data[8] = extended_strut.top_start; + data[9] = extended_strut.top_end; + data[10] = extended_strut.bottom_start; + data[11] = extended_strut.bottom_end; + + XChangeProperty(p->display, p->window, net_wm_extended_strut, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) data, 12); +} + + +void NETWinInfo::setStrut(NETStrut strut) { + if (role != Client) return; + + p->strut = strut; + + long data[4]; + data[0] = strut.left; + data[1] = strut.right; + data[2] = strut.top; + data[3] = strut.bottom; + + XChangeProperty(p->display, p->window, net_wm_strut, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) data, 4); +} + + +void NETWinInfo::setState(unsigned long state, unsigned long mask) { + if (p->mapping_state_dirty) + updateWMState(); + + // setState() needs to know the current state, so read it even if not requested + if( ( p->properties[ PROTOCOLS ] & WMState ) == 0 ) { + p->properties[ PROTOCOLS ] |= WMState; + unsigned long props[ PROPERTIES_SIZE ] = { WMState, 0 }; + assert( PROPERTIES_SIZE == 2 ); // add elements above + update( props ); + p->properties[ PROTOCOLS ] &= ~WMState; + } + + if (role == Client && p->mapping_state != Withdrawn) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETWinInfo::setState (0x%lx, 0x%lx) (Client)\n", + state, mask); +#endif // NETWMDEBUG + + XEvent e; + e.xclient.type = ClientMessage; + e.xclient.message_type = net_wm_state; + e.xclient.display = p->display; + e.xclient.window = p->window; + e.xclient.format = 32; + e.xclient.data.l[3] = 0l; + e.xclient.data.l[4] = 0l; + + if ((mask & Modal) && ((p->state & Modal) != (state & Modal))) { + e.xclient.data.l[0] = (state & Modal) ? 1 : 0; + e.xclient.data.l[1] = net_wm_state_modal; + e.xclient.data.l[2] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } + + if ((mask & Sticky) && ((p->state & Sticky) != (state & Sticky))) { + e.xclient.data.l[0] = (state & Sticky) ? 1 : 0; + e.xclient.data.l[1] = net_wm_state_sticky; + e.xclient.data.l[2] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } + + if ((mask & Max) && (( (p->state&mask) & Max) != (state & Max))) { + + unsigned long wishstate = (p->state & ~mask) | (state & mask); + if ( ( (wishstate & MaxHoriz) != (p->state & MaxHoriz) ) + && ( (wishstate & MaxVert) != (p->state & MaxVert) ) ) { + if ( (wishstate & Max) == Max ) { + e.xclient.data.l[0] = 1; + e.xclient.data.l[1] = net_wm_state_max_horiz; + e.xclient.data.l[2] = net_wm_state_max_vert; + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } else if ( (wishstate & Max) == 0 ) { + e.xclient.data.l[0] = 0; + e.xclient.data.l[1] = net_wm_state_max_horiz; + e.xclient.data.l[2] = net_wm_state_max_vert; + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } else { + e.xclient.data.l[0] = ( wishstate & MaxHoriz ) ? 1 : 0; + e.xclient.data.l[1] = net_wm_state_max_horiz; + e.xclient.data.l[2] = 0; + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + e.xclient.data.l[0] = ( wishstate & MaxVert ) ? 1 : 0; + e.xclient.data.l[1] = net_wm_state_max_vert; + e.xclient.data.l[2] = 0; + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } + } else if ( (wishstate & MaxVert) != (p->state & MaxVert) ) { + e.xclient.data.l[0] = ( wishstate & MaxVert ) ? 1 : 0; + e.xclient.data.l[1] = net_wm_state_max_vert; + e.xclient.data.l[2] = 0; + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } else if ( (wishstate & MaxHoriz) != (p->state & MaxHoriz) ) { + e.xclient.data.l[0] = ( wishstate & MaxHoriz ) ? 1 : 0; + e.xclient.data.l[1] = net_wm_state_max_horiz; + e.xclient.data.l[2] = 0; + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } + } + + if ((mask & Shaded) && ((p->state & Shaded) != (state & Shaded))) { + e.xclient.data.l[0] = (state & Shaded) ? 1 : 0; + e.xclient.data.l[1] = net_wm_state_shaded; + e.xclient.data.l[2] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } + + if ((mask & SkipTaskbar) && + ((p->state & SkipTaskbar) != (state & SkipTaskbar))) { + e.xclient.data.l[0] = (state & SkipTaskbar) ? 1 : 0; + e.xclient.data.l[1] = net_wm_state_skip_taskbar; + e.xclient.data.l[2] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } + + if ((mask & SkipPager) && + ((p->state & SkipPager) != (state & SkipPager))) { + e.xclient.data.l[0] = (state & SkipPager) ? 1 : 0; + e.xclient.data.l[1] = net_wm_state_skip_pager; + e.xclient.data.l[2] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } + + if ((mask & Hidden) && + ((p->state & Hidden) != (state & Hidden))) { + e.xclient.data.l[0] = (state & Hidden) ? 1 : 0; + e.xclient.data.l[1] = net_wm_state_hidden; + e.xclient.data.l[2] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } + + if ((mask & FullScreen) && + ((p->state & FullScreen) != (state & FullScreen))) { + e.xclient.data.l[0] = (state & FullScreen) ? 1 : 0; + e.xclient.data.l[1] = net_wm_state_fullscreen; + e.xclient.data.l[2] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } + + if ((mask & KeepAbove) && + ((p->state & KeepAbove) != (state & KeepAbove))) { + e.xclient.data.l[0] = (state & KeepAbove) ? 1 : 0; + e.xclient.data.l[1] = net_wm_state_above; + e.xclient.data.l[2] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } + + if ((mask & KeepBelow) && + ((p->state & KeepBelow) != (state & KeepBelow))) { + e.xclient.data.l[0] = (state & KeepBelow) ? 1 : 0; + e.xclient.data.l[1] = net_wm_state_below; + e.xclient.data.l[2] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } + + if ((mask & StaysOnTop) && ((p->state & StaysOnTop) != (state & StaysOnTop))) { + e.xclient.data.l[0] = (state & StaysOnTop) ? 1 : 0; + e.xclient.data.l[1] = net_wm_state_stays_on_top; + e.xclient.data.l[2] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } + + if ((mask & DemandsAttention) && + ((p->state & DemandsAttention) != (state & DemandsAttention))) { + e.xclient.data.l[0] = (state & DemandsAttention) ? 1 : 0; + e.xclient.data.l[1] = net_wm_state_demands_attention; + e.xclient.data.l[2] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } + + } else { + p->state &= ~mask; + p->state |= state; + + long data[50]; + int count = 0; + + // hints + if (p->state & Modal) data[count++] = net_wm_state_modal; + if (p->state & MaxVert) data[count++] = net_wm_state_max_vert; + if (p->state & MaxHoriz) data[count++] = net_wm_state_max_horiz; + if (p->state & Shaded) data[count++] = net_wm_state_shaded; + if (p->state & Hidden) data[count++] = net_wm_state_hidden; + if (p->state & FullScreen) data[count++] = net_wm_state_fullscreen; + if (p->state & DemandsAttention) data[count++] = net_wm_state_demands_attention; + + // policy + if (p->state & KeepAbove) data[count++] = net_wm_state_above; + if (p->state & KeepBelow) data[count++] = net_wm_state_below; + if (p->state & StaysOnTop) data[count++] = net_wm_state_stays_on_top; + if (p->state & Sticky) data[count++] = net_wm_state_sticky; + if (p->state & SkipTaskbar) data[count++] = net_wm_state_skip_taskbar; + if (p->state & SkipPager) data[count++] = net_wm_state_skip_pager; + +#ifdef NETWMDEBUG + fprintf(stderr, "NETWinInfo::setState: setting state property (%d)\n", count); + for (int i = 0; i < count; i++) { + char* data_ret = XGetAtomName(p->display, (Atom) data[i]); + fprintf(stderr, "NETWinInfo::setState: state %ld '%s'\n", + data[i], data_ret); + if ( data_ret ) + XFree( data_ret ); + } + +#endif + + XChangeProperty(p->display, p->window, net_wm_state, XA_ATOM, 32, + PropModeReplace, (unsigned char *) data, count); + } +} + + +void NETWinInfo::setWindowType(WindowType type) { + if (role != Client) return; + + int len; + long data[2]; + + switch (type) { + case Override: + // spec extension: override window type. we must comply with the spec + // and provide a fall back (normal seems best) + data[0] = kde_net_wm_window_type_override; + data[1] = net_wm_window_type_normal; + len = 2; + break; + + case Dialog: + data[0] = net_wm_window_type_dialog; + data[1] = None; + len = 1; + break; + + case Menu: + data[0] = net_wm_window_type_menu; + data[1] = None; + len = 1; + break; + + case TopMenu: + // spec extension: override window type. we must comply with the spec + // and provide a fall back (dock seems best) + data[0] = kde_net_wm_window_type_topmenu; + data[1] = net_wm_window_type_dock; + len = 2; + break; + + case Tool: + data[0] = net_wm_window_type_toolbar; + data[1] = None; + len = 1; + break; + + case Dock: + data[0] = net_wm_window_type_dock; + data[1] = None; + len = 1; + break; + + case Desktop: + data[0] = net_wm_window_type_desktop; + data[1] = None; + len = 1; + break; + + case Utility: + data[0] = net_wm_window_type_utility; + data[1] = net_wm_window_type_dialog; // fallback for old netwm version + len = 2; + break; + + case Splash: + data[0] = net_wm_window_type_splash; + data[1] = net_wm_window_type_dock; // fallback (dock seems best) + len = 2; + break; + + case DropdownMenu: + data[0] = net_wm_window_type_dropdown_menu; + data[1] = None; + len = 1; + break; + + case PopupMenu: + data[0] = net_wm_window_type_popup_menu; + data[1] = None; + len = 1; + break; + + case Tooltip: + data[0] = net_wm_window_type_tooltip; + data[1] = None; + len = 1; + break; + + case Notification: + data[0] = net_wm_window_type_notification; + data[1] = None; + len = 1; + break; + + case ComboBox: + data[0] = net_wm_window_type_combobox; + data[1] = None; + len = 1; + break; + + case DNDIcon: + data[0] = net_wm_window_type_dnd; + data[1] = None; + len = 1; + break; + + default: + case Normal: + data[0] = net_wm_window_type_normal; + data[1] = None; + len = 1; + break; + } + + XChangeProperty(p->display, p->window, net_wm_window_type, XA_ATOM, 32, + PropModeReplace, (unsigned char *) &data, len); +} + + +void NETWinInfo::setName(const char *name) { + if (role != Client) return; + + delete [] p->name; + p->name = nstrdup(name); + if( p->name[ 0 ] != '\0' ) + XChangeProperty(p->display, p->window, net_wm_name, UTF8_STRING, 8, + PropModeReplace, (unsigned char *) p->name, + strlen(p->name)); + else + XDeleteProperty(p->display, p->window, net_wm_name); +} + + +void NETWinInfo::setVisibleName(const char *visibleName) { + if (role != WindowManager) return; + + delete [] p->visible_name; + p->visible_name = nstrdup(visibleName); + if( p->visible_name[ 0 ] != '\0' ) + XChangeProperty(p->display, p->window, net_wm_visible_name, UTF8_STRING, 8, + PropModeReplace, (unsigned char *) p->visible_name, + strlen(p->visible_name)); + else + XDeleteProperty(p->display, p->window, net_wm_visible_name); +} + + +void NETWinInfo::setIconName(const char *iconName) { + if (role != Client) return; + + delete [] p->icon_name; + p->icon_name = nstrdup(iconName); + if( p->icon_name[ 0 ] != '\0' ) + XChangeProperty(p->display, p->window, net_wm_icon_name, UTF8_STRING, 8, + PropModeReplace, (unsigned char *) p->icon_name, + strlen(p->icon_name)); + else + XDeleteProperty(p->display, p->window, net_wm_icon_name); +} + + +void NETWinInfo::setVisibleIconName(const char *visibleIconName) { + if (role != WindowManager) return; + + delete [] p->visible_icon_name; + p->visible_icon_name = nstrdup(visibleIconName); + if( p->visible_icon_name[ 0 ] != '\0' ) + XChangeProperty(p->display, p->window, net_wm_visible_icon_name, UTF8_STRING, 8, + PropModeReplace, (unsigned char *) p->visible_icon_name, + strlen(p->visible_icon_name)); + else + XDeleteProperty(p->display, p->window, net_wm_visible_icon_name); +} + + +void NETWinInfo::setDesktop(int desktop) { + if (p->mapping_state_dirty) + updateWMState(); + + if (role == Client && p->mapping_state != Withdrawn) { + // we only send a ClientMessage if we are 1) a client and 2) managed + + if ( desktop == 0 ) + return; // we can't do that while being managed + + XEvent e; + + e.xclient.type = ClientMessage; + e.xclient.message_type = net_wm_desktop; + e.xclient.display = p->display; + e.xclient.window = p->window; + e.xclient.format = 32; + e.xclient.data.l[0] = desktop == OnAllDesktops ? OnAllDesktops : desktop - 1; + e.xclient.data.l[1] = 0l; + e.xclient.data.l[2] = 0l; + e.xclient.data.l[3] = 0l; + e.xclient.data.l[4] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } else { + // otherwise we just set or remove the property directly + p->desktop = desktop; + long d = desktop; + + if ( d != OnAllDesktops ) { + if ( d == 0 ) { + XDeleteProperty( p->display, p->window, net_wm_desktop ); + return; + } + + d -= 1; + } + + XChangeProperty(p->display, p->window, net_wm_desktop, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) &d, 1); + } +} + + +void NETWinInfo::setPid(int pid) { + if (role != Client) return; + + p->pid = pid; + long d = pid; + XChangeProperty(p->display, p->window, net_wm_pid, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) &d, 1); +} + + +void NETWinInfo::setHandledIcons(Bool handled) { + if (role != Client) return; + + p->handled_icons = handled; + long d = handled; + XChangeProperty(p->display, p->window, net_wm_handled_icons, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) &d, 1); +} + +void NETWinInfo::setStartupId(const char* id) { + if (role != Client) return; + + delete[] p->startup_id; + p->startup_id = nstrdup(id); + XChangeProperty(p->display, p->window, net_startup_id, UTF8_STRING, 8, + PropModeReplace, reinterpret_cast< unsigned char* >( p->startup_id ), + strlen( p->startup_id )); +} + +void NETWinInfo::setAllowedActions( unsigned long actions ) { + if( role != WindowManager ) + return; + long data[50]; + int count = 0; + + p->allowed_actions = actions; + if (p->allowed_actions & ActionMove) data[count++] = net_wm_action_move; + if (p->allowed_actions & ActionResize) data[count++] = net_wm_action_resize; + if (p->allowed_actions & ActionMinimize) data[count++] = net_wm_action_minimize; + if (p->allowed_actions & ActionShade) data[count++] = net_wm_action_shade; + if (p->allowed_actions & ActionStick) data[count++] = net_wm_action_stick; + if (p->allowed_actions & ActionMaxVert) data[count++] = net_wm_action_max_vert; + if (p->allowed_actions & ActionMaxHoriz) data[count++] = net_wm_action_max_horiz; + if (p->allowed_actions & ActionFullScreen) data[count++] = net_wm_action_fullscreen; + if (p->allowed_actions & ActionChangeDesktop) data[count++] = net_wm_action_change_desk; + if (p->allowed_actions & ActionClose) data[count++] = net_wm_action_close; + +#ifdef NETWMDEBUG + fprintf(stderr, "NETWinInfo::setAllowedActions: setting property (%d)\n", count); + for (int i = 0; i < count; i++) { + char* data_ret = XGetAtomName(p->display, (Atom) data[i]); + fprintf(stderr, "NETWinInfo::setAllowedActions: action %ld '%s'\n", + data[i], data_ret); + if ( data_ret ) + XFree(data_ret); + } +#endif + + XChangeProperty(p->display, p->window, net_wm_allowed_actions, XA_ATOM, 32, + PropModeReplace, (unsigned char *) data, count); +} + +void NETWinInfo::setKDESystemTrayWinFor(Window window) { + if (role != Client) return; + + p->kde_system_tray_win_for = window; + XChangeProperty(p->display, p->window, kde_net_wm_system_tray_window_for, + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(p->kde_system_tray_win_for), 1); +} + + +void NETWinInfo::setKDEFrameStrut(NETStrut strut) { + setFrameExtents( strut ); +} + +void NETWinInfo::setFrameExtents(NETStrut strut) { + if (role != WindowManager) return; + + p->frame_strut = strut; + + long d[4]; + d[0] = strut.left; + d[1] = strut.right; + d[2] = strut.top; + d[3] = strut.bottom; + + XChangeProperty(p->display, p->window, net_frame_extents, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) d, 4); + XChangeProperty(p->display, p->window, kde_net_wm_frame_strut, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) d, 4); +} + + +void NETWinInfo::kdeGeometry(NETRect& frame, NETRect& window) { + if (p->win_geom.size.width == 0 || p->win_geom.size.height == 0) { + Window unused; + int x, y; + unsigned int w, h, junk; + XGetGeometry(p->display, p->window, &unused, &x, &y, &w, &h, &junk, &junk); + XTranslateCoordinates(p->display, p->window, p->root, 0, 0, &x, &y, &unused + ); + + p->win_geom.pos.x = x; + p->win_geom.pos.y = y; + + p->win_geom.size.width = w; + p->win_geom.size.height = h; + } +// TODO try to work also without _KDE_NET_WM_FRAME_STRUT + window = p->win_geom; + + frame.pos.x = window.pos.x - p->frame_strut.left; + frame.pos.y = window.pos.y - p->frame_strut.top; + frame.size.width = window.size.width + p->frame_strut.left + p->frame_strut.right; + frame.size.height = window.size.height + p->frame_strut.top + p->frame_strut.bottom; +} + + +NETIcon NETWinInfo::icon(int width, int height) const { + return iconInternal( p->icons, p->icon_count, width, height ); +} + +NETIcon NETWinInfo::iconInternal(NETRArray<NETIcon>& icons, int icon_count, int width, int height) const { + NETIcon result; + + if ( !icon_count ) { + result.size.width = 0; + result.size.height = 0; + result.data = 0; + return result; + } + + // find the largest icon + result = icons[0]; + for (int i = 1; i < icons.size(); i++) { + if( icons[i].size.width >= result.size.width && + icons[i].size.height >= result.size.height ) + result = icons[i]; + } + + // return the largest icon if w and h are -1 + if (width == -1 && height == -1) return result; + + // find the icon that's closest in size to w x h... + for (int i = 0; i < icons.size(); i++) { + if ((icons[i].size.width >= width && + icons[i].size.width < result.size.width) && + (icons[i].size.height >= height && + icons[i].size.height < result.size.height)) + result = icons[i]; + } + + return result; +} + +void NETWinInfo::setUserTime( Time time ) { + if (role != Client) return; + + p->user_time = time; + long d = time; + XChangeProperty(p->display, p->window, net_wm_user_time, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) &d, 1); +} + + +unsigned long NETWinInfo::event(XEvent *ev ) +{ + unsigned long props[ 1 ]; + event( ev, props, 1 ); + return props[ 0 ]; +} + +void NETWinInfo::event(XEvent *event, unsigned long* properties, int properties_size ) { + unsigned long props[ PROPERTIES_SIZE ] = { 0, 0 }; + assert( PROPERTIES_SIZE == 2 ); // add elements above + unsigned long& dirty = props[ PROTOCOLS ]; + unsigned long& dirty2 = props[ PROTOCOLS2 ]; + bool do_update = false; + + if (role == WindowManager && event->type == ClientMessage && + event->xclient.format == 32) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETWinInfo::event: handling ClientMessage event\n"); +#endif // NETWMDEBUG + + if (event->xclient.message_type == net_wm_state) { + dirty = WMState; + + // we need to generate a change mask + +#ifdef NETWMDEBUG + fprintf(stderr, + "NETWinInfo::event: state client message, getting new state/mask\n"); +#endif + + int i; + long state = 0, mask = 0; + + for (i = 1; i < 3; i++) { +#ifdef NETWMDEBUG + char* debug_txt = XGetAtomName(p->display, (Atom) event->xclient.data.l[i]); + fprintf(stderr, "NETWinInfo::event: message %ld '%s'\n", + event->xclient.data.l[i], debug_txt ); + if ( debug_txt ) + XFree( debug_txt ); +#endif + + if ((Atom) event->xclient.data.l[i] == net_wm_state_modal) + mask |= Modal; + else if ((Atom) event->xclient.data.l[i] == net_wm_state_sticky) + mask |= Sticky; + else if ((Atom) event->xclient.data.l[i] == net_wm_state_max_vert) + mask |= MaxVert; + else if ((Atom) event->xclient.data.l[i] == net_wm_state_max_horiz) + mask |= MaxHoriz; + else if ((Atom) event->xclient.data.l[i] == net_wm_state_shaded) + mask |= Shaded; + else if ((Atom) event->xclient.data.l[i] == net_wm_state_skip_taskbar) + mask |= SkipTaskbar; + else if ((Atom) event->xclient.data.l[i] == net_wm_state_skip_pager) + mask |= SkipPager; + else if ((Atom) event->xclient.data.l[i] == net_wm_state_hidden) + mask |= Hidden; + else if ((Atom) event->xclient.data.l[i] == net_wm_state_fullscreen) + mask |= FullScreen; + else if ((Atom) event->xclient.data.l[i] == net_wm_state_above) + mask |= KeepAbove; + else if ((Atom) event->xclient.data.l[i] == net_wm_state_below) + mask |= KeepBelow; + else if ((Atom) event->xclient.data.l[i] == net_wm_state_demands_attention) + mask |= DemandsAttention; + else if ((Atom) event->xclient.data.l[i] == net_wm_state_stays_on_top) + mask |= StaysOnTop; + } + + // when removing, we just leave newstate == 0 + switch (event->xclient.data.l[0]) { + case 1: // set + // to set... the change state should be the same as the mask + state = mask; + break; + + case 2: // toggle + // to toggle, we need to xor the current state with the new state + state = (p->state & mask) ^ mask; + break; + + default: + // to clear state, the new state should stay zero + ; + } + +#ifdef NETWMDEBUG + fprintf(stderr, "NETWinInfo::event: calling changeState(%lx, %lx)\n", + state, mask); +#endif + + changeState(state, mask); + } else if (event->xclient.message_type == net_wm_desktop) { + dirty = WMDesktop; + + if( event->xclient.data.l[0] == OnAllDesktops ) + changeDesktop( OnAllDesktops ); + else + changeDesktop(event->xclient.data.l[0] + 1); + } + } + + if (event->type == PropertyNotify) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETWinInfo::event: handling PropertyNotify event\n"); +#endif + + XEvent pe = *event; + + Bool done = False; + Bool compaction = False; + while (! done) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETWinInfo::event: loop fire\n"); +#endif + + if (pe.xproperty.atom == net_wm_name) + dirty |= WMName; + else if (pe.xproperty.atom == net_wm_visible_name) + dirty |= WMVisibleName; + else if (pe.xproperty.atom == net_wm_desktop) + dirty |= WMDesktop; + else if (pe.xproperty.atom == net_wm_window_type) + dirty |=WMWindowType; + else if (pe.xproperty.atom == net_wm_state) + dirty |= WMState; + else if (pe.xproperty.atom == net_wm_strut) + dirty |= WMStrut; + else if (pe.xproperty.atom == net_wm_extended_strut) + dirty2 |= WM2ExtendedStrut; + else if (pe.xproperty.atom == net_wm_icon_geometry) + dirty |= WMIconGeometry; + else if (pe.xproperty.atom == net_wm_icon) + dirty |= WMIcon; + else if (pe.xproperty.atom == net_wm_pid) + dirty |= WMPid; + else if (pe.xproperty.atom == net_wm_handled_icons) + dirty |= WMHandledIcons; + else if (pe.xproperty.atom == net_startup_id) + dirty2 |= WM2StartupId; + else if (pe.xproperty.atom == net_wm_allowed_actions) + dirty2 |= WM2AllowedActions; + else if (pe.xproperty.atom == kde_net_wm_system_tray_window_for) + dirty |= WMKDESystemTrayWinFor; + else if (pe.xproperty.atom == xa_wm_state) + dirty |= XAWMState; + else if (pe.xproperty.atom == net_frame_extents) + dirty |= WMFrameExtents; + else if (pe.xproperty.atom == kde_net_wm_frame_strut) + dirty |= WMKDEFrameStrut; + else if (pe.xproperty.atom == net_wm_icon_name) + dirty |= WMIconName; + else if (pe.xproperty.atom == net_wm_visible_icon_name) + dirty |= WMVisibleIconName; + else if (pe.xproperty.atom == net_wm_user_time) + dirty2 |= WM2UserTime; + else if (pe.xproperty.atom == XA_WM_HINTS) + dirty2 |= WM2GroupLeader; + else if (pe.xproperty.atom == XA_WM_TRANSIENT_FOR) + dirty2 |= WM2TransientFor; + else if (pe.xproperty.atom == XA_WM_CLASS) + dirty2 |= WM2WindowClass; + else if (pe.xproperty.atom == wm_window_role) + dirty2 |= WM2WindowRole; + else if (pe.xproperty.atom == XA_WM_CLIENT_MACHINE) + dirty2 |= WM2ClientMachine; + else { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETWinInfo::event: putting back event and breaking\n"); +#endif + + if ( compaction ) + XPutBackEvent(p->display, &pe); + break; + } + + if (XCheckTypedWindowEvent(p->display, p->window, PropertyNotify, &pe) ) + compaction = True; + else + break; + } + + do_update = true; + } else if (event->type == ConfigureNotify) { + +#ifdef NETWMDEBUG + fprintf(stderr, "NETWinInfo::event: handling ConfigureNotify event\n"); +#endif + + dirty |= WMGeometry; + + // update window geometry + p->win_geom.pos.x = event->xconfigure.x; + p->win_geom.pos.y = event->xconfigure.y; + p->win_geom.size.width = event->xconfigure.width; + p->win_geom.size.height = event->xconfigure.height; + } + + if( do_update ) + update( props ); + + if( properties_size > PROPERTIES_SIZE ) + properties_size = PROPERTIES_SIZE; + for( int i = 0; + i < properties_size; + ++i ) + properties[ i ] = props[ i ]; +} + +void NETWinInfo::updateWMState() { + unsigned long props[ PROPERTIES_SIZE ] = { XAWMState, 0 }; + assert( PROPERTIES_SIZE == 2 ); // add elements above + update( props ); +} + +void NETWinInfo::update(const unsigned long dirty_props[]) { + Atom type_ret; + int format_ret; + unsigned long nitems_ret, unused; + unsigned char *data_ret; + unsigned long props[ PROPERTIES_SIZE ]; + for( int i = 0; + i < PROPERTIES_SIZE; + ++i ) + props[ i ] = dirty_props[ i ] & p->properties[ i ]; + const unsigned long& dirty = props[ PROTOCOLS ]; + const unsigned long& dirty2 = props[ PROTOCOLS2 ]; + + // we *always* want to update WM_STATE if set in dirty_props + if( dirty_props[ PROTOCOLS ] & XAWMState ) + props[ PROTOCOLS ] |= XAWMState; + + if (dirty & XAWMState) { + p->mapping_state = Withdrawn; + if (XGetWindowProperty(p->display, p->window, xa_wm_state, 0l, 1l, + False, xa_wm_state, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == xa_wm_state && format_ret == 32 && + nitems_ret == 1) { + long *state = (long *) data_ret; + + switch(*state) { + case IconicState: + p->mapping_state = Iconic; + break; + case NormalState: + p->mapping_state = Visible; + break; + case WithdrawnState: + default: + p->mapping_state = Withdrawn; + break; + } + + p->mapping_state_dirty = False; + } + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & WMState) { + p->state = 0; + if (XGetWindowProperty(p->display, p->window, net_wm_state, 0l, 2048l, + False, XA_ATOM, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_ATOM && format_ret == 32 && nitems_ret > 0) { + // determine window state +#ifdef NETWMDEBUG + fprintf(stderr, "NETWinInfo::update: updating window state (%ld)\n", + nitems_ret); +#endif + + long *states = (long *) data_ret; + unsigned long count; + + for (count = 0; count < nitems_ret; count++) { +#ifdef NETWMDEBUG + char* data_ret = XGetAtomName(p->display, (Atom) states[count]); + fprintf(stderr, + "NETWinInfo::update: adding window state %ld '%s'\n", + states[count], data_ret ); + if ( data_ret ) + XFree( data_ret ); +#endif + + if ((Atom) states[count] == net_wm_state_modal) + p->state |= Modal; + else if ((Atom) states[count] == net_wm_state_sticky) + p->state |= Sticky; + else if ((Atom) states[count] == net_wm_state_max_vert) + p->state |= MaxVert; + else if ((Atom) states[count] == net_wm_state_max_horiz) + p->state |= MaxHoriz; + else if ((Atom) states[count] == net_wm_state_shaded) + p->state |= Shaded; + else if ((Atom) states[count] == net_wm_state_skip_taskbar) + p->state |= SkipTaskbar; + else if ((Atom) states[count] == net_wm_state_skip_pager) + p->state |= SkipPager; + else if ((Atom) states[count] == net_wm_state_hidden) + p->state |= Hidden; + else if ((Atom) states[count] == net_wm_state_fullscreen) + p->state |= FullScreen; + else if ((Atom) states[count] == net_wm_state_above) + p->state |= KeepAbove; + else if ((Atom) states[count] == net_wm_state_below) + p->state |= KeepBelow; + else if ((Atom) states[count] == net_wm_state_demands_attention) + p->state |= DemandsAttention; + else if ((Atom) states[count] == net_wm_state_stays_on_top) + p->state |= StaysOnTop; + } + } + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & WMDesktop) { + p->desktop = 0; + if (XGetWindowProperty(p->display, p->window, net_wm_desktop, 0l, 1l, + False, XA_CARDINAL, &type_ret, + &format_ret, &nitems_ret, + &unused, &data_ret) + == Success) { + if (type_ret == XA_CARDINAL && format_ret == 32 && + nitems_ret == 1) { + p->desktop = *((long *) data_ret); + if ((signed) p->desktop != OnAllDesktops) + p->desktop++; + + if ( p->desktop == 0 ) + p->desktop = OnAllDesktops; + } + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & WMName) { + delete[] p->name; + p->name = NULL; + if (XGetWindowProperty(p->display, p->window, net_wm_name, 0l, + MAX_PROP_SIZE, False, UTF8_STRING, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == UTF8_STRING && format_ret == 8 && nitems_ret > 0) { + p->name = nstrndup((const char *) data_ret, nitems_ret); + } + + if( data_ret ) + XFree(data_ret); + } + } + + if (dirty & WMVisibleName) { + delete[] p->visible_name; + p->visible_name = NULL; + if (XGetWindowProperty(p->display, p->window, net_wm_visible_name, 0l, + MAX_PROP_SIZE, False, UTF8_STRING, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == UTF8_STRING && format_ret == 8 && nitems_ret > 0) { + p->visible_name = nstrndup((const char *) data_ret, nitems_ret); + } + + if( data_ret ) + XFree(data_ret); + } + } + + if (dirty & WMIconName) { + delete[] p->icon_name; + p->icon_name = NULL; + if (XGetWindowProperty(p->display, p->window, net_wm_icon_name, 0l, + MAX_PROP_SIZE, False, UTF8_STRING, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == UTF8_STRING && format_ret == 8 && nitems_ret > 0) { + p->icon_name = nstrndup((const char *) data_ret, nitems_ret); + } + + if( data_ret ) + XFree(data_ret); + } + } + + if (dirty & WMVisibleIconName) + { + delete[] p->visible_icon_name; + p->visible_icon_name = NULL; + if (XGetWindowProperty(p->display, p->window, net_wm_visible_icon_name, 0l, + MAX_PROP_SIZE, False, UTF8_STRING, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == UTF8_STRING && format_ret == 8 && nitems_ret > 0) { + p->visible_icon_name = nstrndup((const char *) data_ret, nitems_ret); + } + + if( data_ret ) + XFree(data_ret); + } + } + + if (dirty & WMWindowType) { + p->types.reset(); + p->types[ 0 ] = Unknown; + p->has_net_support = false; + if (XGetWindowProperty(p->display, p->window, net_wm_window_type, 0l, 2048l, + False, XA_ATOM, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_ATOM && format_ret == 32 && nitems_ret > 0) { + // determine the window type +#ifdef NETWMDEBUG + fprintf(stderr, "NETWinInfo::update: getting window type (%ld)\n", + nitems_ret); +#endif + + p->has_net_support = true; + + unsigned long count = 0; + long *types = (long *) data_ret; + int pos = 0; + + while (count < nitems_ret) { + // remember all window types we know +#ifdef NETWMDEBUG + char* debug_type = XGetAtomName(p->display, (Atom) types[count]); + fprintf(stderr, + "NETWinInfo::update: examining window type %ld %s\n", + types[count], debug_type ); + if ( debug_type ) + XFree( debug_type ); +#endif + + if ((Atom) types[count] == net_wm_window_type_normal) + p->types[ pos++ ] = Normal; + else if ((Atom) types[count] == net_wm_window_type_desktop) + p->types[ pos++ ] = Desktop; + else if ((Atom) types[count] == net_wm_window_type_dock) + p->types[ pos++ ] = Dock; + else if ((Atom) types[count] == net_wm_window_type_toolbar) + p->types[ pos++ ] = Tool; + else if ((Atom) types[count] == net_wm_window_type_menu) + p->types[ pos++ ] = Menu; + else if ((Atom) types[count] == net_wm_window_type_dialog) + p->types[ pos++ ] = Dialog; + else if ((Atom) types[count] == net_wm_window_type_utility) + p->types[ pos++ ] = Utility; + else if ((Atom) types[count] == net_wm_window_type_splash) + p->types[ pos++ ] = Splash; + else if ((Atom) types[count] == net_wm_window_type_dropdown_menu) + p->types[ pos++ ] = DropdownMenu; + else if ((Atom) types[count] == net_wm_window_type_popup_menu) + p->types[ pos++ ] = PopupMenu; + else if ((Atom) types[count] == net_wm_window_type_tooltip) + p->types[ pos++ ] = Tooltip; + else if ((Atom) types[count] == net_wm_window_type_notification) + p->types[ pos++ ] = Notification; + else if ((Atom) types[count] == net_wm_window_type_combobox) + p->types[ pos++ ] = ComboBox; + else if ((Atom) types[count] == net_wm_window_type_dnd) + p->types[ pos++ ] = DNDIcon; + else if ((Atom) types[count] == kde_net_wm_window_type_override) + p->types[ pos++ ] = Override; + else if ((Atom) types[count] == kde_net_wm_window_type_topmenu) + p->types[ pos++ ] = TopMenu; + + count++; + } + } + + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & WMStrut) { + p->strut = NETStrut(); + if (XGetWindowProperty(p->display, p->window, net_wm_strut, 0l, 4l, + False, XA_CARDINAL, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_CARDINAL && format_ret == 32 && + nitems_ret == 4) { + long *d = (long *) data_ret; + p->strut.left = d[0]; + p->strut.right = d[1]; + p->strut.top = d[2]; + p->strut.bottom = d[3]; + } + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty2 & WM2ExtendedStrut) { + p->extended_strut = NETExtendedStrut(); + if (XGetWindowProperty(p->display, p->window, net_wm_extended_strut, 0l, 12l, + False, XA_CARDINAL, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_CARDINAL && format_ret == 32 && + nitems_ret == 12) { + long *d = (long *) data_ret; + p->extended_strut.left_width = d[0]; + p->extended_strut.right_width = d[1]; + p->extended_strut.top_width = d[2]; + p->extended_strut.bottom_width = d[3]; + p->extended_strut.left_start = d[4]; + p->extended_strut.left_end = d[5]; + p->extended_strut.right_start = d[6]; + p->extended_strut.right_end = d[7]; + p->extended_strut.top_start = d[8]; + p->extended_strut.top_end = d[9]; + p->extended_strut.bottom_start = d[10]; + p->extended_strut.bottom_end = d[11]; + } + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & WMIconGeometry) { + p->icon_geom = NETRect(); + if (XGetWindowProperty(p->display, p->window, net_wm_icon_geometry, 0l, 4l, + False, XA_CARDINAL, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_CARDINAL && format_ret == 32 && + nitems_ret == 4) { + long *d = (long *) data_ret; + p->icon_geom.pos.x = d[0]; + p->icon_geom.pos.y = d[1]; + p->icon_geom.size.width = d[2]; + p->icon_geom.size.height = d[3]; + } + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & WMIcon) { + readIcon(p->display,p->window,net_wm_icon,p->icons,p->icon_count); + } + + if (dirty & WMKDESystemTrayWinFor) { + p->kde_system_tray_win_for = 0; + if (XGetWindowProperty(p->display, p->window, kde_net_wm_system_tray_window_for, + 0l, 1l, False, XA_WINDOW, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_WINDOW && format_ret == 32 && + nitems_ret == 1) { + p->kde_system_tray_win_for = *((Window *) data_ret); + if ( p->kde_system_tray_win_for == 0 ) + p->kde_system_tray_win_for = p->root; + } + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & WMFrameExtents) { + p->frame_strut = NETStrut(); + bool ok = false; + if (XGetWindowProperty(p->display, p->window, net_frame_extents, + 0l, 4l, False, XA_CARDINAL, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) == Success) { + if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 4) { + ok = true; + long *d = (long *) data_ret; + + p->frame_strut.left = d[0]; + p->frame_strut.right = d[1]; + p->frame_strut.top = d[2]; + p->frame_strut.bottom = d[3]; + } + if ( data_ret ) + XFree(data_ret); + } + if (!ok && XGetWindowProperty(p->display, p->window, kde_net_wm_frame_strut, + 0l, 4l, False, XA_CARDINAL, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) == Success) { + if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 4) { + ok = true; + long *d = (long *) data_ret; + + p->frame_strut.left = d[0]; + p->frame_strut.right = d[1]; + p->frame_strut.top = d[2]; + p->frame_strut.bottom = d[3]; + } + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty & WMPid) { + p->pid = 0; + if (XGetWindowProperty(p->display, p->window, net_wm_pid, 0l, 1l, + False, XA_CARDINAL, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) == Success) { + if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 1) { + p->pid = *((long *) data_ret); + } + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty2 & WM2StartupId) + { + delete[] p->startup_id; + p->startup_id = NULL; + if (XGetWindowProperty(p->display, p->window, net_startup_id, 0l, + MAX_PROP_SIZE, False, UTF8_STRING, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == UTF8_STRING && format_ret == 8 && nitems_ret > 0) { + p->startup_id = nstrndup((const char *) data_ret, nitems_ret); + } + + if( data_ret ) + XFree(data_ret); + } + } + + if( dirty2 & WM2AllowedActions ) { + p->allowed_actions = 0; + if (XGetWindowProperty(p->display, p->window, net_wm_allowed_actions, 0l, 2048l, + False, XA_ATOM, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_ATOM && format_ret == 32 && nitems_ret > 0) { + // determine actions +#ifdef NETWMDEBUG + fprintf(stderr, "NETWinInfo::update: updating allowed actions (%ld)\n", + nitems_ret); +#endif + + long *actions = (long *) data_ret; + unsigned long count; + + for (count = 0; count < nitems_ret; count++) { +#ifdef NETWMDEBUG + fprintf(stderr, + "NETWinInfo::update: adding allowed action %ld '%s'\n", + actions[count], + XGetAtomName(p->display, (Atom) actions[count])); +#endif + + if ((Atom) actions[count] == net_wm_action_move) + p->allowed_actions |= ActionMove; + if ((Atom) actions[count] == net_wm_action_resize) + p->allowed_actions |= ActionResize; + if ((Atom) actions[count] == net_wm_action_minimize) + p->allowed_actions |= ActionMinimize; + if ((Atom) actions[count] == net_wm_action_shade) + p->allowed_actions |= ActionShade; + if ((Atom) actions[count] == net_wm_action_stick) + p->allowed_actions |= ActionStick; + if ((Atom) actions[count] == net_wm_action_max_vert) + p->allowed_actions |= ActionMaxVert; + if ((Atom) actions[count] == net_wm_action_max_horiz) + p->allowed_actions |= ActionMaxHoriz; + if ((Atom) actions[count] == net_wm_action_fullscreen) + p->allowed_actions |= ActionFullScreen; + if ((Atom) actions[count] == net_wm_action_change_desk) + p->allowed_actions |= ActionChangeDesktop; + if ((Atom) actions[count] == net_wm_action_close) + p->allowed_actions |= ActionClose; + } + } + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty2 & WM2UserTime) { + p->user_time = -1U; + if (XGetWindowProperty(p->display, p->window, net_wm_user_time, 0l, 1l, + False, XA_CARDINAL, &type_ret, &format_ret, + &nitems_ret, &unused, &data_ret) == Success) { + // don't do nitems_ret check - Qt does PropModeAppend to avoid API call for it + if (type_ret == XA_CARDINAL && format_ret == 32 /*&& nitems_ret == 1*/) { + p->user_time = *((long *) data_ret); + } + if ( data_ret ) + XFree(data_ret); + } + } + + if (dirty2 & WM2TransientFor) { + p->transient_for = None; + XGetTransientForHint(p->display, p->window, &p->transient_for); + } + + if (dirty2 & WM2GroupLeader) { + XWMHints *hints = XGetWMHints(p->display, p->window); + p->window_group = None; + if ( hints ) + { + if( hints->flags & WindowGroupHint ) + p->window_group = hints->window_group; + XFree( reinterpret_cast< char* >( hints )); + } + } + + if( dirty2 & WM2WindowClass ) { + delete[] p->class_class; + delete[] p->class_name; + p->class_class = NULL; + p->class_name = NULL; + XClassHint hint; + if( XGetClassHint( p->display, p->window, &hint )) { + p->class_class = strdup( hint.res_class ); + p->class_name = strdup( hint.res_name ); + XFree( hint.res_class ); + XFree( hint.res_name ); + } + } + + if( dirty2 & WM2WindowRole ) { + delete[] p->role; + p->role = NULL; + if (XGetWindowProperty(p->display, p->window, wm_window_role, 0l, + MAX_PROP_SIZE, False, XA_STRING, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_STRING && format_ret == 8 && nitems_ret > 0) { + p->role = nstrndup((const char *) data_ret, nitems_ret); + } + if( data_ret ) + XFree(data_ret); + } + } + + if( dirty2 & WM2ClientMachine ) { + delete[] p->client_machine; + p->client_machine = NULL; + if (XGetWindowProperty(p->display, p->window, XA_WM_CLIENT_MACHINE, 0l, + MAX_PROP_SIZE, False, XA_STRING, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_STRING && format_ret == 8 && nitems_ret > 0) { + p->client_machine = nstrndup((const char *) data_ret, nitems_ret); + } + if( data_ret ) + XFree(data_ret); + } + } +} + + +NETRect NETWinInfo::iconGeometry() const { + return p->icon_geom; +} + + +unsigned long NETWinInfo::state() const { + return p->state; +} + + +NETStrut NETWinInfo::strut() const { + return p->strut; +} + +NETExtendedStrut NETWinInfo::extendedStrut() const { + return p->extended_strut; +} + +bool NET::typeMatchesMask( WindowType type, unsigned long mask ) { + switch( type ) { +#define CHECK_TYPE_MASK( type ) \ + case type: \ + if( mask & type##Mask ) \ + return true; \ + break; + CHECK_TYPE_MASK( Normal ) + CHECK_TYPE_MASK( Desktop ) + CHECK_TYPE_MASK( Dock ) + CHECK_TYPE_MASK( Toolbar ) + CHECK_TYPE_MASK( Menu ) + CHECK_TYPE_MASK( Dialog ) + CHECK_TYPE_MASK( Override ) + CHECK_TYPE_MASK( TopMenu ) + CHECK_TYPE_MASK( Utility ) + CHECK_TYPE_MASK( Splash ) + CHECK_TYPE_MASK( DropdownMenu ) + CHECK_TYPE_MASK( PopupMenu ) + CHECK_TYPE_MASK( Tooltip ) + CHECK_TYPE_MASK( Notification ) + CHECK_TYPE_MASK( ComboBox ) + CHECK_TYPE_MASK( DNDIcon ) +#undef CHECK_TYPE_MASK + default: + break; + } + return false; +} + +NET::WindowType NETWinInfo::windowType( unsigned long supported_types ) const { + for( int i = 0; + i < p->types.size(); + ++i ) { + // return the type only if the application supports it + if( typeMatchesMask( p->types[ i ], supported_types )) + return p->types[ i ]; + } + return Unknown; +} + +NET::WindowType NETWinInfo::windowType() const { + return p->types[ 0 ]; +} + + +const char *NETWinInfo::name() const { + return p->name; +} + + +const char *NETWinInfo::visibleName() const { + return p->visible_name; +} + + +const char *NETWinInfo::iconName() const { + return p->icon_name; +} + + +const char *NETWinInfo::visibleIconName() const { + return p->visible_icon_name; +} + + +int NETWinInfo::desktop() const { + return p->desktop; +} + +int NETWinInfo::pid() const { + return p->pid; +} + +Time NETWinInfo::userTime() const { + return p->user_time; +} + +const char* NETWinInfo::startupId() const { + return p->startup_id; +} + +unsigned long NETWinInfo::allowedActions() const { + return p->allowed_actions; +} + +bool NETWinInfo::hasNETSupport() const { + return p->has_net_support; +} + +Window NETWinInfo::transientFor() const { + return p->transient_for; +} + +Window NETWinInfo::groupLeader() const { + return p->window_group; +} + +const char* NETWinInfo::windowClassClass() const { + return p->class_class; +} + +const char* NETWinInfo::windowClassName() const { + return p->class_name; +} + +const char* NETWinInfo::windowRole() const { + return p->role; +} + +const char* NETWinInfo::clientMachine() const { + return p->client_machine; +} + +Bool NETWinInfo::handledIcons() const { + return p->handled_icons; +} + + +Window NETWinInfo::kdeSystemTrayWinFor() const { + return p->kde_system_tray_win_for; +} + +const unsigned long* NETWinInfo::passedProperties() const { + return p->properties; +} + +unsigned long NETWinInfo::properties() const { + return p->properties[ PROTOCOLS ]; +} + + +NET::MappingState NETWinInfo::mappingState() const { + return p->mapping_state; +} + +void NETRootInfo::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +void NETWinInfo::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +// Functions for X timestamp comparing. For Time being 32bit they're fairly simple +// (the #if 0 part), but on 64bit architectures Time is 64bit unsigned long, +// so there special care needs to be taken to always use only the lower 32bits. +#if 0 +int NET::timestampCompare( Time time1, Time time2 ) // like strcmp() + { + if( time1 == time2 ) + return 0; + return ( time1 - time2 ) < 0x7fffffffU ? 1 : -1; // time1 > time2 -> 1, handle wrapping + } + +Time NET::timestampDiff( Time time1, Time time2 ) // returns time2 - time1 + { // no need to handle wrapping? + return time2 - time1; + } +#else +int NET::timestampCompare( unsigned long time1_, unsigned long time2_ ) // like strcmp() + { + Q_UINT32 time1 = time1_; + Q_UINT32 time2 = time2_; + if( time1 == time2 ) + return 0; + return Q_UINT32( time1 - time2 ) < 0x7fffffffU ? 1 : -1; // time1 > time2 -> 1, handle wrapping + } + +int NET::timestampDiff( unsigned long time1_, unsigned long time2_ ) // returns time2 - time1 + { // no need to handle wrapping? + Q_UINT32 time1 = time1_; + Q_UINT32 time2 = time2_; + return Q_UINT32( time2 - time1 ); + } +#endif + + +#endif |