2001-09-12 21:43:42 +00:00
/* wmspec.c-- support for the wm-spec Hints
2004-10-12 01:34:32 +00:00
*
2001-09-12 21:43:42 +00:00
* Window Maker window manager
2004-10-12 01:34:32 +00:00
*
2003-01-16 23:30:45 +00:00
* Copyright (c) 1998-2003 Alfredo K. Kojima
2004-10-12 01:34:32 +00:00
*
2001-09-12 21:43:42 +00:00
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
2004-10-12 01:34:32 +00:00
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
2001-09-12 21:43:42 +00:00
* USA.
*/
#include "wconfig.h"
2004-10-12 01:34:32 +00:00
#ifdef NETWM_HINTS
2001-09-12 21:43:42 +00:00
#include <X11/Xlib.h>
#include <X11/Xatom.h>
2004-10-12 01:34:32 +00:00
#include <string.h>
2001-09-12 21:43:42 +00:00
#include "WindowMaker.h"
#include "window.h"
#include "screen.h"
2004-10-12 01:34:32 +00:00
#include "workspace.h"
2001-09-12 21:43:42 +00:00
#include "framewin.h"
#include "actions.h"
2004-10-12 01:34:32 +00:00
#include "client.h"
#include "wmspec.h"
#include "icon.h"
#include "stacking.h"
#include "xinerama.h"
2001-09-12 21:43:42 +00:00
2004-10-12 01:34:32 +00:00
#ifdef DEBUG_WMSPEC
#include <stdio.h>
#endif
/* Global variables */
extern Atom _XA_WM_DELETE_WINDOW ;
extern Time LastTimestamp ;
extern WPreferences wPreferences ;
/* Root Window Properties */
2001-09-12 21:43:42 +00:00
static Atom net_supported ;
static Atom net_client_list ;
static Atom net_client_list_stacking ;
static Atom net_number_of_desktops ;
static Atom net_desktop_geometry ;
static Atom net_desktop_viewport ;
static Atom net_current_desktop ;
2004-10-12 01:34:32 +00:00
static Atom net_desktop_names ;
2001-09-12 21:43:42 +00:00
static Atom net_active_window ;
2004-10-12 01:34:32 +00:00
static Atom net_workarea ; /* XXX: not xinerama compatible */
2001-09-12 21:43:42 +00:00
static Atom net_supporting_wm_check ;
2004-10-12 01:34:32 +00:00
static Atom net_virtual_roots ; /* N/A */
static Atom net_desktop_layout ; /* XXX */
static Atom net_showing_desktop ;
/* Other Root Window Messages */
static Atom net_close_window ;
static Atom net_moveresize_window ; /* TODO */
static Atom net_wm_moveresize ; /* TODO */
/* Application Window Properties */
static Atom net_wm_name ; /* TODO */
static Atom net_wm_visible_name ; /* TODO */
static Atom net_wm_icon_name ; /* TODO */
static Atom net_wm_visible_icon_name ; /* TODO */
2001-09-12 21:43:42 +00:00
static Atom net_wm_desktop ;
2004-10-12 01:34:32 +00:00
static Atom net_wm_window_type ;
static Atom net_wm_window_type_desktop ;
static Atom net_wm_window_type_dock ;
static Atom net_wm_window_type_toolbar ;
static Atom net_wm_window_type_menu ;
static Atom net_wm_window_type_utility ;
static Atom net_wm_window_type_splash ;
static Atom net_wm_window_type_dialog ;
static Atom net_wm_window_type_normal ;
2001-09-12 21:43:42 +00:00
static Atom net_wm_state ;
2004-10-12 01:34:32 +00:00
static Atom net_wm_state_modal ; /* XXX: what is this?!? */
2001-09-12 21:43:42 +00:00
static Atom net_wm_state_sticky ;
static Atom net_wm_state_maximized_vert ;
static Atom net_wm_state_maximized_horz ;
static Atom net_wm_state_shaded ;
static Atom net_wm_state_skip_taskbar ;
static Atom net_wm_state_skip_pager ;
2004-10-12 01:34:32 +00:00
static Atom net_wm_state_hidden ;
static Atom net_wm_state_fullscreen ;
static Atom net_wm_state_above ;
static Atom net_wm_state_below ;
static Atom net_wm_allowed_actions ;
static Atom net_wm_action_move ;
static Atom net_wm_action_resize ;
static Atom net_wm_action_minimize ;
static Atom net_wm_action_shade ;
static Atom net_wm_action_stick ;
static Atom net_wm_action_maximize_horz ;
static Atom net_wm_action_maximize_vert ;
static Atom net_wm_action_fullscreen ;
static Atom net_wm_action_change_desktop ;
static Atom net_wm_action_close ;
static Atom net_wm_strut ; /* XXX: see net_workarea */
static Atom net_wm_strut_partial ; /* TODO: doesn't really fit into the current strut scheme */
static Atom net_wm_icon_geometry ; /* FIXME: should work together with net_wm_handled_icons, gnome-panel-2.2.0.1 doesn't use _NET_WM_HANDLED_ICONS, thus present situation. */
static Atom net_wm_icon ;
static Atom net_wm_pid ; /* TODO */
static Atom net_wm_handled_icons ; /* FIXME: see net_wm_icon_geometry */
/* Window Manager Protocols */
static Atom net_wm_ping ; /* TODO */
static Atom utf8_string ;
typedef struct {
char * name ;
Atom * atom ;
} atomitem_t ;
static atomitem_t atomNames [] = {
{ "_NET_SUPPORTED" , & net_supported },
{ "_NET_CLIENT_LIST" , & net_client_list },
{ "_NET_CLIENT_LIST_STACKING" , & net_client_list_stacking },
{ "_NET_NUMBER_OF_DESKTOPS" , & net_number_of_desktops },
{ "_NET_DESKTOP_GEOMETRY" , & net_desktop_geometry },
{ "_NET_DESKTOP_VIEWPORT" , & net_desktop_viewport },
{ "_NET_CURRENT_DESKTOP" , & net_current_desktop },
{ "_NET_DESKTOP_NAMES" , & net_desktop_names },
{ "_NET_ACTIVE_WINDOW" , & net_active_window },
{ "_NET_WORKAREA" , & net_workarea },
{ "_NET_SUPPORTING_WM_CHECK" , & net_supporting_wm_check },
{ "_NET_VIRTUAL_ROOTS" , & net_virtual_roots },
{ "_NET_DESKTOP_LAYOUT" , & net_desktop_layout },
{ "_NET_SHOWING_DESKTOP" , & net_showing_desktop },
{ "_NET_CLOSE_WINDOW" , & net_close_window },
{ "_NET_MOVERESIZE_WINDOW" , & net_moveresize_window },
{ "_NET_WM_MOVERESIZE" , & net_wm_moveresize },
{ "_NET_WM_NAME" , & net_wm_name },
{ "_NET_WM_VISIBLE_NAME" , & net_wm_visible_name },
{ "_NET_WM_ICON_NAME" , & net_wm_icon_name },
{ "_NET_WM_VISIBLE_ICON_NAME" , & net_wm_visible_icon_name },
{ "_NET_WM_DESKTOP" , & net_wm_desktop },
{ "_NET_WM_WINDOW_TYPE" , & net_wm_window_type },
{ "_NET_WM_WINDOW_TYPE_DESKTOP" , & net_wm_window_type_desktop },
{ "_NET_WM_WINDOW_TYPE_DOCK" , & net_wm_window_type_dock },
{ "_NET_WM_WINDOW_TYPE_TOOLBAR" , & net_wm_window_type_toolbar },
{ "_NET_WM_WINDOW_TYPE_MENU" , & net_wm_window_type_menu },
{ "_NET_WM_WINDOW_TYPE_UTILITY" , & net_wm_window_type_utility },
{ "_NET_WM_WINDOW_TYPE_SPLASH" , & net_wm_window_type_splash },
{ "_NET_WM_WINDOW_TYPE_DIALOG" , & net_wm_window_type_dialog },
{ "_NET_WM_WINDOW_TYPE_NORMAL" , & net_wm_window_type_normal },
{ "_NET_WM_STATE" , & net_wm_state },
{ "_NET_WM_STATE_MODAL" , & net_wm_state_modal },
{ "_NET_WM_STATE_STICKY" , & net_wm_state_sticky },
{ "_NET_WM_STATE_MAXIMIZED_VERT" , & net_wm_state_maximized_vert },
{ "_NET_WM_STATE_MAXIMIZED_HORZ" , & net_wm_state_maximized_horz },
{ "_NET_WM_STATE_SHADED" , & net_wm_state_shaded },
{ "_NET_WM_STATE_SKIP_TASKBAR" , & net_wm_state_skip_taskbar },
{ "_NET_WM_STATE_SKIP_PAGER" , & net_wm_state_skip_pager },
{ "_NET_WM_STATE_HIDDEN" , & net_wm_state_hidden },
{ "_NET_WM_STATE_FULLSCREEN" , & net_wm_state_fullscreen },
{ "_NET_WM_STATE_ABOVE" , & net_wm_state_above },
{ "_NET_WM_STATE_BELOW" , & net_wm_state_below },
{ "_NET_WM_ALLOWED_ACTIONS" , & net_wm_allowed_actions },
{ "_NET_WM_ACTION_MOVE" , & net_wm_action_move },
{ "_NET_WM_ACTION_RESIZE" , & net_wm_action_resize },
{ "_NET_WM_ACTION_MINIMIZE" , & net_wm_action_minimize },
{ "_NET_WM_ACTION_SHADE" , & net_wm_action_shade },
{ "_NET_WM_ACTION_STICK" , & net_wm_action_stick },
{ "_NET_WM_ACTION_MAXIMIZE_HORZ" , & net_wm_action_maximize_horz },
{ "_NET_WM_ACTION_MAXIMIZE_VERT" , & net_wm_action_maximize_vert },
{ "_NET_WM_ACTION_FULLSCREEN" , & net_wm_action_fullscreen },
{ "_NET_WM_ACTION_CHANGE_DESKTOP" , & net_wm_action_change_desktop },
{ "_NET_WM_ACTION_CLOSE" , & net_wm_action_close },
{ "_NET_WM_STRUT" , & net_wm_strut },
{ "_NET_WM_STRUT_PARTIAL" , & net_wm_strut_partial },
{ "_NET_WM_ICON_GEOMETRY" , & net_wm_icon_geometry },
{ "_NET_WM_ICON" , & net_wm_icon },
{ "_NET_WM_PID" , & net_wm_pid },
{ "_NET_WM_HANDLED_ICONS" , & net_wm_handled_icons },
{ "_NET_WM_PING" , & net_wm_ping },
{ "UTF8_STRING" , & utf8_string },
};
2001-09-12 21:43:42 +00:00
2004-10-12 01:34:32 +00:00
#define atomNr (sizeof(atomNames)/sizeof(atomitem_t))
2001-09-12 21:43:42 +00:00
2004-10-12 01:34:32 +00:00
#define _NET_WM_STATE_REMOVE 0
#define _NET_WM_STATE_ADD 1
#define _NET_WM_STATE_TOGGLE 2
2001-09-12 21:43:42 +00:00
2004-10-12 01:34:32 +00:00
#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
#define _NET_WM_MOVERESIZE_SIZE_TOP 1
#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
#define _NET_WM_MOVERESIZE_SIZE_LEFT 7
#define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */
#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */
#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */
2001-09-12 21:43:42 +00:00
static void observer ( void * self , WMNotification * notif );
static void wsobserver ( void * self , WMNotification * notif );
2004-10-12 01:34:32 +00:00
static void updateClientList ( WScreen * scr );
static void updateClientListStacking ( WScreen * scr , WWindow * );
static void updateWorkspaceNames ( WScreen * scr );
static void updateCurrentWorkspace ( WScreen * scr );
static void updateWorkspaceCount ( WScreen * scr );
2001-09-12 21:43:42 +00:00
typedef struct NetData {
WScreen * scr ;
2004-10-12 01:34:32 +00:00
WReservedArea * strut ;
WWindow ** show_desktop ;
2001-09-12 21:43:42 +00:00
} NetData ;
2004-10-12 01:34:32 +00:00
static void
setSupportedHints ( WScreen * scr )
2001-09-12 21:43:42 +00:00
{
2004-10-12 01:34:32 +00:00
Atom atom [ atomNr ];
2001-09-12 21:43:42 +00:00
int i = 0 ;
2004-10-12 01:34:32 +00:00
2001-09-12 21:43:42 +00:00
/* set supported hints list */
2004-10-12 01:34:32 +00:00
/* XXX: extend this !!! */
2001-09-12 21:43:42 +00:00
atom [ i ++ ] = net_client_list ;
2004-10-12 01:34:32 +00:00
atom [ i ++ ] = net_client_list_stacking ;
atom [ i ++ ] = net_number_of_desktops ;
atom [ i ++ ] = net_desktop_geometry ;
atom [ i ++ ] = net_desktop_viewport ;
atom [ i ++ ] = net_current_desktop ;
atom [ i ++ ] = net_desktop_names ;
atom [ i ++ ] = net_active_window ;
atom [ i ++ ] = net_workarea ;
atom [ i ++ ] = net_supporting_wm_check ;
atom [ i ++ ] = net_showing_desktop ;
#if 0
atom[i++] = net_wm_moveresize;
#endif
atom [ i ++ ] = net_wm_desktop ;
atom [ i ++ ] = net_wm_window_type ;
atom [ i ++ ] = net_wm_window_type_desktop ;
atom [ i ++ ] = net_wm_window_type_dock ;
atom [ i ++ ] = net_wm_window_type_toolbar ;
atom [ i ++ ] = net_wm_window_type_menu ;
atom [ i ++ ] = net_wm_window_type_utility ;
atom [ i ++ ] = net_wm_window_type_splash ;
atom [ i ++ ] = net_wm_window_type_dialog ;
atom [ i ++ ] = net_wm_window_type_normal ;
atom [ i ++ ] = net_wm_state ;
/* atom[i++] = net_wm_state_modal; */ /* XXX: not sure where/when to use it. */
atom [ i ++ ] = net_wm_state_sticky ;
atom [ i ++ ] = net_wm_state_shaded ;
atom [ i ++ ] = net_wm_state_maximized_horz ;
atom [ i ++ ] = net_wm_state_maximized_vert ;
atom [ i ++ ] = net_wm_state_skip_taskbar ;
atom [ i ++ ] = net_wm_state_skip_pager ;
atom [ i ++ ] = net_wm_state_hidden ;
atom [ i ++ ] = net_wm_state_fullscreen ;
atom [ i ++ ] = net_wm_state_above ;
atom [ i ++ ] = net_wm_state_below ;
atom [ i ++ ] = net_wm_allowed_actions ;
atom [ i ++ ] = net_wm_action_move ;
atom [ i ++ ] = net_wm_action_resize ;
atom [ i ++ ] = net_wm_action_minimize ;
atom [ i ++ ] = net_wm_action_shade ;
atom [ i ++ ] = net_wm_action_stick ;
atom [ i ++ ] = net_wm_action_maximize_horz ;
atom [ i ++ ] = net_wm_action_maximize_vert ;
atom [ i ++ ] = net_wm_action_fullscreen ;
atom [ i ++ ] = net_wm_action_change_desktop ;
atom [ i ++ ] = net_wm_action_close ;
atom [ i ++ ] = net_wm_strut ;
atom [ i ++ ] = net_wm_icon_geometry ;
atom [ i ++ ] = net_wm_icon ;
atom [ i ++ ] = net_wm_handled_icons ;
XChangeProperty ( dpy , scr -> root_win , net_supported , XA_ATOM , 32 ,
PropModeReplace , ( unsigned char * ) atom , i );
2001-09-12 21:43:42 +00:00
/* set supporting wm hint */
2004-10-12 01:34:32 +00:00
XChangeProperty ( dpy , scr -> root_win , net_supporting_wm_check , XA_WINDOW , 32 ,
PropModeReplace , ( unsigned char * ) & scr -> info_window , 1 );
XChangeProperty ( dpy , scr -> info_window , net_supporting_wm_check , XA_WINDOW ,
32 , PropModeReplace , ( unsigned char * ) & scr -> info_window , 1 );
}
void
wNETWMUpdateDesktop ( WScreen * scr )
{
CARD32 * views , sizes [ 2 ];
int count , i ;
if ( scr -> workspace_count == 0 )
return ;
count = scr -> workspace_count * 2 ;
views = wmalloc ( sizeof ( CARD32 ) * count );
/*memset(views, 0, sizeof(CARD32) * count);*/
#ifdef VIRTUAL_DESKTOP
sizes [ 0 ] = scr -> workspaces [ scr -> current_workspace ] -> width ;
sizes [ 1 ] = scr -> workspaces [ scr -> current_workspace ] -> height ;
#else
2001-09-12 21:43:42 +00:00
sizes [ 0 ] = scr -> scr_width ;
sizes [ 1 ] = scr -> scr_height ;
2004-10-12 01:34:32 +00:00
#endif
for ( i = 0 ; i < scr -> workspace_count ; i ++ ) {
#ifdef VIRTUAL_DESKTOP
views [ 2 * i + 0 ] = scr -> workspaces [ i ] -> view_x ;
views [ 2 * i + 1 ] = scr -> workspaces [ i ] -> view_y ;
#else
views [ 2 * i + 0 ] = 0 ;
views [ 2 * i + 1 ] = 0 ;
#endif
}
XChangeProperty ( dpy , scr -> root_win , net_desktop_geometry , XA_CARDINAL , 32 ,
PropModeReplace , ( unsigned char * ) sizes , 2 );
XChangeProperty ( dpy , scr -> root_win , net_desktop_viewport , XA_CARDINAL , 32 ,
PropModeReplace , ( unsigned char * ) views , count );
wfree ( views );
}
static void
updateIconImage ( WScreen * scr , WWindow * wwin )
{
Atom actual_type_return ;
int actual_format_return ;
unsigned long nitems_return , bytes_after_return ;
unsigned char * prop_return ;
int rc = XGetWindowProperty ( dpy , wwin -> client_win , net_wm_icon , 0 , ~ 0 , False ,
XA_CARDINAL , & actual_type_return , & actual_format_return ,
& nitems_return , & bytes_after_return , & prop_return );
if ( rc == Success && prop_return ) {
unsigned int * data = ( unsigned int * ) prop_return ;
unsigned int pos = 0 , len = 0 ;
unsigned int best_pos = 0 , best_tmp = ~ 0 ;
extern WPreferences wPreferences ;
unsigned int pref_size = wPreferences . icon_size ;
unsigned int pref_sq = pref_size * pref_size ;
char * src , * dst ;
RImage * new_rimage ;
do {
len = data [ pos + 0 ] * data [ pos + 1 ];
unsigned int tmp = pref_sq - len ;
if ( tmp < best_tmp && tmp > 0 ) {
best_tmp = tmp ;
best_pos = pos ;
}
pos += 2 + len ;
} while ( pos < nitems_return && len != 0 );
new_rimage = RCreateImage ( data [ best_pos + 0 ], data [ best_pos + 1 ], True );
len = data [ best_pos + 0 ] * data [ best_pos + 1 ];
src = ( char * ) & data [ best_pos + 2 ];
dst = new_rimage -> data ;
for ( pos = 0 ; pos < len ; ++ pos , src += 4 , dst += 4 ) {
dst [ 0 ] = src [ 2 ]; /* R */
dst [ 1 ] = src [ 1 ]; /* G */
dst [ 2 ] = src [ 0 ]; /* B */
dst [ 3 ] = src [ 3 ]; /* A */
}
if ( new_rimage ) {
if ( wwin -> net_icon_image )
RReleaseImage ( wwin -> net_icon_image );
wwin -> net_icon_image = new_rimage ;
}
XFree ( prop_return );
}
}
2001-09-12 21:43:42 +00:00
2004-10-12 01:34:32 +00:00
static void
updateShowDesktop ( WScreen * scr , Bool show )
{
CARD32 foo ;
2001-09-12 21:43:42 +00:00
2004-10-12 01:34:32 +00:00
foo = ( show == True );
XChangeProperty ( dpy , scr -> root_win , net_showing_desktop , XA_CARDINAL , 32 ,
PropModeReplace , ( unsigned char * ) & foo , 1 );
2001-09-12 21:43:42 +00:00
}
2004-10-12 01:34:32 +00:00
void
wNETWMShowingDesktop ( WScreen * scr , Bool show )
{
if ( show && scr -> netdata -> show_desktop == NULL ) {
WWindow * tmp , ** wins ;
int i = 0 ;
wins = ( WWindow ** ) wmalloc ( sizeof ( WWindow * ) * ( scr -> window_count + 1 ));
tmp = scr -> focused_window ;
while ( tmp ) {
if ( ! tmp -> flags . hidden && ! tmp -> flags . miniaturized &&
! WFLAGP ( tmp , skip_window_list )) {
wins [ i ++ ] = tmp ;
tmp -> flags . skip_next_animation = 1 ;
tmp -> flags . net_show_desktop = 1 ;
wIconifyWindow ( tmp );
}
tmp = tmp -> prev ;
}
wins [ i ++ ] = NULL ;
scr -> netdata -> show_desktop = wins ;
updateShowDesktop ( scr , True );
} else if ( scr -> netdata -> show_desktop != NULL ) {
/* FIXME: get rid of workspace flashing ! */
int ws = scr -> current_workspace ;
WWindow ** tmp ;
for ( tmp = scr -> netdata -> show_desktop ; * tmp ; ++ tmp ) {
wDeiconifyWindow ( * tmp );
( * tmp ) -> flags . net_show_desktop = 0 ;
}
if ( ws != scr -> current_workspace )
wWorkspaceChange ( scr , ws );
wfree ( scr -> netdata -> show_desktop );
scr -> netdata -> show_desktop = NULL ;
updateShowDesktop ( scr , False );
}
}
void
wNETWMInitStuff ( WScreen * scr )
2001-09-12 21:43:42 +00:00
{
NetData * data ;
2004-10-12 01:34:32 +00:00
int i ;
#ifdef DEBUG_WMSPEC
printf ( "wNETWMInitStuff \n " );
#endif
2001-09-12 21:43:42 +00:00
#ifdef HAVE_XINTERNATOMS
{
2004-10-12 01:34:32 +00:00
Atom atoms [ atomNr ];
char * names [ atomNr ];
for ( i = 0 ; i < atomNr ; ++ i ) {
names [ i ] = atomNames [ i ]. name ;
}
XInternAtoms ( dpy , & names [ 0 ], atomNr , False , atoms );
for ( i = 0 ; i < atomNr ; ++ i ) {
* atomNames [ i ]. atom = atoms [ i ];
}
}
#else
for ( i = 0 ; i < atomNr ; i ++ ) {
* atomNames [ i ]. atom = XInternAtom ( dpy , atomNames [ i ]. name , False );
2001-09-12 21:43:42 +00:00
}
#endif
2004-10-12 01:34:32 +00:00
2001-09-12 21:43:42 +00:00
data = wmalloc ( sizeof ( NetData ));
data -> scr = scr ;
2004-10-12 01:34:32 +00:00
data -> strut = NULL ;
data -> show_desktop = NULL ;
scr -> netdata = data ;
setSupportedHints ( scr );
2001-09-12 21:43:42 +00:00
WMAddNotificationObserver ( observer , data , WMNManaged , NULL );
WMAddNotificationObserver ( observer , data , WMNUnmanaged , NULL );
WMAddNotificationObserver ( observer , data , WMNChangedWorkspace , NULL );
WMAddNotificationObserver ( observer , data , WMNChangedState , NULL );
WMAddNotificationObserver ( observer , data , WMNChangedFocus , NULL );
WMAddNotificationObserver ( observer , data , WMNChangedStacking , NULL );
WMAddNotificationObserver ( observer , data , WMNChangedName , NULL );
WMAddNotificationObserver ( wsobserver , data , WMNWorkspaceCreated , NULL );
WMAddNotificationObserver ( wsobserver , data , WMNWorkspaceDestroyed , NULL );
WMAddNotificationObserver ( wsobserver , data , WMNWorkspaceChanged , NULL );
WMAddNotificationObserver ( wsobserver , data , WMNWorkspaceNameChanged , NULL );
2004-10-12 01:34:32 +00:00
updateClientList ( scr );
updateClientListStacking ( scr , NULL );
updateWorkspaceCount ( scr );
updateCurrentWorkspace ( scr );
updateWorkspaceNames ( scr );
updateShowDesktop ( scr , False );
wScreenUpdateUsableArea ( scr );
2001-09-12 21:43:42 +00:00
}
void
2004-10-12 01:34:32 +00:00
wNETWMUpdateActions ( WWindow * wwin , Bool del )
2001-09-12 21:43:42 +00:00
{
2004-10-12 01:34:32 +00:00
Atom action [ 10 ]; /* nr of actions atoms defined */
int i = 0 ;
if ( del ) {
XDeleteProperty ( dpy , wwin -> client_win , net_wm_allowed_actions );
return ;
}
if ( IS_MOVABLE ( wwin ))
action [ i ++ ] = net_wm_action_move ;
if ( IS_RESIZABLE ( wwin ))
action [ i ++ ] = net_wm_action_resize ;
if ( ! WFLAGP ( wwin , no_miniaturizable ))
action [ i ++ ] = net_wm_action_minimize ;
if ( ! WFLAGP ( wwin , no_shadeable ))
action [ i ++ ] = net_wm_action_shade ;
/* if (!WFLAGP(wwin, no_stickable)) */
action [ i ++ ] = net_wm_action_stick ;
/* if (!(WFLAGP(wwin, no_maximizeable) & MAX_HORIZONTAL)) */
if ( IS_RESIZABLE ( wwin ))
action [ i ++ ] = net_wm_action_maximize_horz ;
/* if (!(WFLAGP(wwin, no_maximizeable) & MAX_VERTICAL)) */
if ( IS_RESIZABLE ( wwin ))
action [ i ++ ] = net_wm_action_maximize_vert ;
/* if (!WFLAGP(wwin, no_fullscreen)) */
action [ i ++ ] = net_wm_action_fullscreen ;
/* if (!WFLAGP(wwin, no_change_desktop)) */
action [ i ++ ] = net_wm_action_change_desktop ;
if ( ! WFLAGP ( wwin , no_closable ))
action [ i ++ ] = net_wm_action_close ;
XChangeProperty ( dpy , wwin -> client_win , net_wm_allowed_actions ,
XA_ATOM , 32 , PropModeReplace , ( unsigned char * ) action , i );
}
void
wNETWMUpdateWorkarea ( WScreen * scr , WArea usableArea )
{
CARD32 * area ;
int count , i ;
/* XXX: not Xinerama compatible,
xinerama gets the largest available */
if ( ! scr -> netdata || scr -> workspace_count == 0 )
return ;
count = scr -> workspace_count * 4 ;
area = wmalloc ( sizeof ( CARD32 ) * count );
for ( i = 0 ; i < scr -> workspace_count ; i ++ ) {
area [ 4 * i + 0 ] = usableArea . x1 ;
area [ 4 * i + 1 ] = usableArea . y1 ;
area [ 4 * i + 2 ] = usableArea . x2 - usableArea . x1 ;
area [ 4 * i + 3 ] = usableArea . y2 - usableArea . y1 ;
}
2001-09-12 21:43:42 +00:00
XChangeProperty ( dpy , scr -> root_win , net_workarea , XA_CARDINAL , 32 ,
2004-10-12 01:34:32 +00:00
PropModeReplace , ( unsigned char * ) area , count );
wfree ( area );
2001-09-12 21:43:42 +00:00
}
2004-10-12 01:34:32 +00:00
Bool
wNETWMGetUsableArea ( WScreen * scr , int head , WArea * area )
{
WReservedArea * cur ;
WMRect rect ;
if ( ! scr -> netdata || ! scr -> netdata -> strut )
return False ;
area -> x1 = area -> y1 = area -> x2 = area -> y2 = 0 ;
for ( cur = scr -> netdata -> strut ; cur ; cur = cur -> next ) {
WWindow * wwin = wWindowFor ( cur -> window );
if ( wWindowTouchesHead ( wwin , head )) {
if ( cur -> area . x1 > area -> x1 )
area -> x1 = cur -> area . x1 ;
if ( cur -> area . y1 > area -> y1 )
area -> y1 = cur -> area . y1 ;
if ( cur -> area . x2 > area -> x2 )
area -> x2 = cur -> area . x2 ;
if ( cur -> area . y2 > area -> y2 )
area -> y2 = cur -> area . y2 ;
}
}
if ( area -> x1 == 0 && area -> x2 == 0 &&
area -> y1 == 0 && area -> y2 == 0 ) return False ;
rect = wGetRectForHead ( scr , head );
area -> x1 = rect . pos . x + area -> x1 ;
area -> x2 = rect . pos . x + rect . size . width - area -> x2 ;
area -> y1 = rect . pos . y + area -> y1 ;
area -> y2 = rect . pos . y + rect . size . height - area -> y2 ;
return True ;
}
2001-09-12 21:43:42 +00:00
static void
2004-10-12 01:34:32 +00:00
updateClientList ( WScreen * scr )
2001-09-12 21:43:42 +00:00
{
2004-10-12 01:34:32 +00:00
WWindow * wwin ;
Window * windows ;
int count ;
2001-09-12 21:43:42 +00:00
2004-10-12 01:34:32 +00:00
windows = ( Window * ) wmalloc ( sizeof ( Window ) * ( scr -> window_count + 1 ));
2001-09-12 21:43:42 +00:00
2004-10-12 01:34:32 +00:00
count = 0 ;
wwin = scr -> focused_window ;
while ( wwin ) {
windows [ count ++ ] = wwin -> client_win ;
wwin = wwin -> prev ;
2001-09-12 21:43:42 +00:00
}
2004-10-12 01:34:32 +00:00
XChangeProperty ( dpy , scr -> root_win , net_client_list , XA_WINDOW , 32 ,
PropModeReplace , ( unsigned char * ) windows , count );
wfree ( windows );
2001-09-12 21:43:42 +00:00
XFlush ( dpy );
}
static void
2004-10-12 01:34:32 +00:00
updateClientListStacking ( WScreen * scr , WWindow * wwin_excl )
2001-09-12 21:43:42 +00:00
{
WWindow * wwin ;
Window * client_list ;
2004-10-12 01:34:32 +00:00
Window * client_list_reverse ;
2001-09-12 21:43:42 +00:00
int client_count ;
WCoreWindow * tmp ;
WMBagIterator iter ;
2004-10-12 01:34:32 +00:00
int i ;
2001-09-12 21:43:42 +00:00
/* update client list */
2004-10-12 01:34:32 +00:00
i = scr -> window_count + 1 ;
client_list = ( Window * ) wmalloc ( sizeof ( Window ) * i );
client_list_reverse = ( Window * ) wmalloc ( sizeof ( Window ) * i );
2001-09-12 21:43:42 +00:00
2004-10-12 01:34:32 +00:00
client_count = 0 ;
2001-09-12 21:43:42 +00:00
WM_ETARETI_BAG ( scr -> stacking_list , tmp , iter ) {
2004-10-12 01:34:32 +00:00
while ( tmp ) {
wwin = wWindowFor ( tmp -> window );
/* wwin_excl is a window to exclude from the list
(e.g. it's now unmanaged) */
if ( wwin && ( wwin != wwin_excl ))
client_list [ client_count ++ ] = wwin -> client_win ;
tmp = tmp -> stacking -> under ;
}
2001-09-12 21:43:42 +00:00
}
2004-10-12 01:34:32 +00:00
for ( i = 0 ; i < client_count ; i ++ ) {
Window w = client_list [ client_count - i - 1 ];
client_list_reverse [ i ] = w ;
}
XChangeProperty ( dpy , scr -> root_win , net_client_list_stacking , XA_WINDOW , 32 ,
PropModeReplace , ( unsigned char * ) client_list_reverse , client_count );
2001-09-12 21:43:42 +00:00
wfree ( client_list );
2004-10-12 01:34:32 +00:00
wfree ( client_list_reverse );
2001-09-12 21:43:42 +00:00
XFlush ( dpy );
}
static void
updateWorkspaceCount ( WScreen * scr ) /* changeable */
{
2004-10-12 01:34:32 +00:00
CARD32 count ;
count = scr -> workspace_count ;
XChangeProperty ( dpy , scr -> root_win , net_number_of_desktops , XA_CARDINAL ,
32 , PropModeReplace , ( unsigned char * ) & count , 1 );
2001-09-12 21:43:42 +00:00
}
static void
updateCurrentWorkspace ( WScreen * scr ) /* changeable */
{
2004-10-12 01:34:32 +00:00
CARD32 count ;
count = scr -> current_workspace ;
XChangeProperty ( dpy , scr -> root_win , net_current_desktop , XA_CARDINAL , 32 ,
PropModeReplace , ( unsigned char * ) & count , 1 );
2001-09-12 21:43:42 +00:00
}
static void
2004-10-12 01:34:32 +00:00
updateWorkspaceNames ( WScreen * scr )
2001-09-12 21:43:42 +00:00
{
2004-10-12 01:34:32 +00:00
char buf [ 1024 ], * pos ;
unsigned int i , len , curr_size ;
pos = buf ;
len = 0 ;
for ( i = 0 ; i < scr -> workspace_count ; i ++ ) {
curr_size = strlen ( scr -> workspaces [ i ] -> name );
strcpy ( pos , scr -> workspaces [ i ] -> name );
pos += ( curr_size + 1 );
len += ( curr_size + 1 );
}
XChangeProperty ( dpy , scr -> root_win , net_desktop_names , utf8_string , 8 ,
PropModeReplace , ( unsigned char * ) buf , len );
2001-09-12 21:43:42 +00:00
}
static void
updateFocusHint ( WScreen * scr , WWindow * wwin ) /* changeable */
{
2004-10-12 01:34:32 +00:00
Window window ;
if ( ! scr -> focused_window || ! scr -> focused_window -> flags . focused )
window = None ;
else
window = scr -> focused_window -> client_win ;
XChangeProperty ( dpy , scr -> root_win , net_active_window , XA_WINDOW , 32 ,
PropModeReplace , ( unsigned char * ) & window , 1 );
2001-09-12 21:43:42 +00:00
}
static void
2004-10-12 01:34:32 +00:00
updateWorkspaceHint ( WWindow * wwin , Bool fake , Bool del )
2001-09-12 21:43:42 +00:00
{
2004-10-12 01:34:32 +00:00
CARD32 l ;
2001-09-12 21:43:42 +00:00
if ( del ) {
2004-10-12 01:34:32 +00:00
XDeleteProperty ( dpy , wwin -> client_win , net_wm_desktop );
2001-09-12 21:43:42 +00:00
} else {
2004-10-12 01:34:32 +00:00
l = (( fake || IS_OMNIPRESENT ( wwin )) ? - 1 : wwin -> frame -> workspace );
XChangeProperty ( dpy , wwin -> client_win , net_wm_desktop , XA_CARDINAL ,
32 , PropModeReplace , ( unsigned char * ) & l , 1 );
2001-09-12 21:43:42 +00:00
}
}
static void
2004-10-12 01:34:32 +00:00
updateStateHint ( WWindow * wwin , Bool changedWorkspace , Bool del ) /* changeable */
2001-09-12 21:43:42 +00:00
{
if ( del ) {
2004-10-12 01:34:32 +00:00
if ( ! wwin -> flags . net_state_from_client ) {
XDeleteProperty ( dpy , wwin -> client_win , net_wm_state );
}
2001-09-12 21:43:42 +00:00
} else {
2004-10-12 01:34:32 +00:00
Atom state [ 11 ]; /* nr of defined state atoms */
int i = 0 ;
if ( changedWorkspace || ( wPreferences . sticky_icons && ! IS_OMNIPRESENT ( wwin )))
updateWorkspaceHint ( wwin , False , False );
if ( IS_OMNIPRESENT ( wwin ))
state [ i ++ ] = net_wm_state_sticky ;
if ( wwin -> flags . shaded )
state [ i ++ ] = net_wm_state_shaded ;
if ( wwin -> flags . maximized & MAX_HORIZONTAL )
state [ i ++ ] = net_wm_state_maximized_horz ;
if ( wwin -> flags . maximized & MAX_VERTICAL )
state [ i ++ ] = net_wm_state_maximized_vert ;
if ( WFLAGP ( wwin , skip_window_list ))
state [ i ++ ] = net_wm_state_skip_taskbar ;
if ( wwin -> flags . net_skip_pager )
state [ i ++ ] = net_wm_state_skip_pager ;
if (( wwin -> flags . hidden || wwin -> flags . miniaturized ) && ! wwin -> flags . net_show_desktop ){
state [ i ++ ] = net_wm_state_hidden ;
state [ i ++ ] = net_wm_state_skip_pager ;
if ( wwin -> flags . miniaturized && wPreferences . sticky_icons ) {
if ( ! IS_OMNIPRESENT ( wwin ))
updateWorkspaceHint ( wwin , True , False );
state [ i ++ ] = net_wm_state_sticky ;
}
}
if ( WFLAGP ( wwin , sunken ))
state [ i ++ ] = net_wm_state_below ;
if ( WFLAGP ( wwin , floating ))
state [ i ++ ] = net_wm_state_above ;
if ( wwin -> flags . fullscreen )
state [ i ++ ] = net_wm_state_fullscreen ;
XChangeProperty ( dpy , wwin -> client_win , net_wm_state , XA_ATOM , 32 ,
PropModeReplace , ( unsigned char * ) state , i );
2001-09-12 21:43:42 +00:00
}
}
2004-10-12 01:34:32 +00:00
static Bool
2001-09-12 21:43:42 +00:00
updateStrut ( WWindow * wwin , Bool adding )
{
2004-10-12 01:34:32 +00:00
WScreen * scr ;
WReservedArea * area ;
Bool hasState = False ;
scr = wwin -> screen_ptr ;
if ( adding ) {
Atom type_ret ;
int fmt_ret ;
unsigned long nitems_ret ;
unsigned long bytes_after_ret ;
long * data = 0 ;
if ( XGetWindowProperty ( dpy , wwin -> client_win , net_wm_strut , 0 , 4 , False ,
XA_CARDINAL , & type_ret , & fmt_ret , & nitems_ret ,
& bytes_after_ret ,
( unsigned char ** ) & data ) == Success && data ) {
area = ( WReservedArea * ) wmalloc ( sizeof ( WReservedArea ));
area -> area . x1 = data [ 0 ];
area -> area . x2 = data [ 1 ];
area -> area . y1 = data [ 2 ];
area -> area . y2 = data [ 3 ];
area -> window = wwin -> client_win ;
area -> next = scr -> netdata -> strut ;
scr -> netdata -> strut = area ;
XFree ( data );
hasState = True ;
#ifdef VIRTUAL_DESKTOP
/* just in case wm_window_type didn't set it already */
wwin -> client_flags . virtual_stick = 1 ;
#endif
}
2001-09-12 21:43:42 +00:00
} else {
2004-10-12 01:34:32 +00:00
/* deleting */
area = scr -> netdata -> strut ;
if ( area ) {
if ( area -> window == wwin -> client_win ) {
scr -> netdata -> strut = area -> next ;
wfree ( area );
hasState = True ;
} else {
while ( area -> next && area -> next -> window != wwin -> client_win )
area = area -> next ;
if ( area -> next ) {
WReservedArea * next ;
next = area -> next -> next ;
wfree ( area -> next );
area -> next = next ;
hasState = True ;
}
}
}
}
return hasState ;
}
static int
getWindowLayer ( WWindow * wwin )
{
int layer = WMNormalLevel ;
if ( wwin -> type == net_wm_window_type_desktop ) {
layer = WMDesktopLevel ;
} else if ( wwin -> type == net_wm_window_type_dock ) {
layer = WMDockLevel ;
} else if ( wwin -> type == net_wm_window_type_toolbar ) {
layer = WMMainMenuLevel ;
} else if ( wwin -> type == net_wm_window_type_menu ) {
layer = WMSubmenuLevel ;
} else if ( wwin -> type == net_wm_window_type_utility ) {
} else if ( wwin -> type == net_wm_window_type_splash ) {
} else if ( wwin -> type == net_wm_window_type_dialog ) {
if ( wwin -> transient_for ) {
WWindow * parent = wWindowFor ( wwin -> transient_for );
if ( parent && parent -> flags . fullscreen ) {
layer = WMFullscreenLevel ;
}
}
//layer = WMPopUpLevel;
} else if ( wwin -> type == net_wm_window_type_normal ) {
}
if ( wwin -> client_flags . sunken && WMSunkenLevel < layer )
layer = WMSunkenLevel ;
if ( wwin -> client_flags . floating && WMFloatingLevel > layer )
layer = WMFloatingLevel ;
return layer ;
}
static void
doStateAtom ( WWindow * wwin , Atom state , int set , Bool init )
{
if ( state == net_wm_state_sticky ) {
if ( set == _NET_WM_STATE_TOGGLE ) {
set = ! IS_OMNIPRESENT ( wwin );
}
if ( set != wwin -> flags . omnipresent ) {
wWindowSetOmnipresent ( wwin , set );
}
} else if ( state == net_wm_state_shaded ) {
if ( set == _NET_WM_STATE_TOGGLE ) {
set = ! wwin -> flags . shaded ;
}
if ( init ) {
wwin -> flags . shaded = set ;
} else {
if ( set ) {
wShadeWindow ( wwin );
} else {
wUnshadeWindow ( wwin );
}
}
} else if ( state == net_wm_state_skip_taskbar ) {
if ( set == _NET_WM_STATE_TOGGLE ) {
set = ! wwin -> client_flags . skip_window_list ;
}
wwin -> client_flags . skip_window_list = set ;
} else if ( state == net_wm_state_skip_pager ) {
if ( set == _NET_WM_STATE_TOGGLE ) {
set = ! wwin -> flags . net_skip_pager ;
}
wwin -> flags . net_skip_pager = set ;
} else if ( state == net_wm_state_maximized_vert ) {
if ( set == _NET_WM_STATE_TOGGLE ) {
set = ! ( wwin -> flags . maximized & MAX_VERTICAL );
}
if ( init ) {
wwin -> flags . maximized = set ;
} else {
if ( set ) {
wMaximizeWindow ( wwin , wwin -> flags . maximized | MAX_VERTICAL );
} else {
wMaximizeWindow ( wwin , wwin -> flags . maximized & ~ MAX_VERTICAL );
}
}
} else if ( state == net_wm_state_maximized_horz ) {
if ( set == _NET_WM_STATE_TOGGLE ) {
set = ! ( wwin -> flags . maximized & MAX_HORIZONTAL );
}
if ( init ) {
wwin -> flags . maximized = set ;
} else {
if ( set ) {
wMaximizeWindow ( wwin , wwin -> flags . maximized | MAX_HORIZONTAL );
} else {
wMaximizeWindow ( wwin , wwin -> flags . maximized & ~ MAX_HORIZONTAL );
}
}
} else if ( state == net_wm_state_hidden ) {
if ( set == _NET_WM_STATE_TOGGLE ) {
set = ! ( wwin -> flags . miniaturized );
}
if ( init ) {
wwin -> flags . miniaturized = set ;
} else {
if ( set ) {
wIconifyWindow ( wwin );
} else {
wDeiconifyWindow ( wwin );
}
}
} else if ( state == net_wm_state_fullscreen ) {
if ( set == _NET_WM_STATE_TOGGLE ) {
set = ! ( wwin -> flags . fullscreen );
}
if ( init ) {
wwin -> flags . fullscreen = set ;
} else {
if ( set ) {
wFullscreenWindow ( wwin );
} else {
wUnfullscreenWindow ( wwin );
}
}
} else if ( state == net_wm_state_above ) {
if ( set == _NET_WM_STATE_TOGGLE ) {
set = ! ( wwin -> client_flags . floating );
}
if ( init ) {
wwin -> client_flags . floating = set ;
} else {
wwin -> client_flags . floating = set ;
ChangeStackingLevel ( wwin -> frame -> core , getWindowLayer ( wwin ));
}
} else if ( state == net_wm_state_below ) {
if ( set == _NET_WM_STATE_TOGGLE ) {
set = ! ( wwin -> client_flags . sunken );
}
if ( init ) {
wwin -> client_flags . sunken = set ;
} else {
wwin -> client_flags . sunken = set ;
ChangeStackingLevel ( wwin -> frame -> core , getWindowLayer ( wwin ));
}
} else {
#ifdef DEBUG_WMSPEC
printf ( "doStateAtom unknown atom %s set %d \n " , XGetAtomName ( dpy , state ), set );
#endif
2001-09-12 21:43:42 +00:00
}
}
2004-10-12 01:34:32 +00:00
static void
removeIcon ( WWindow * wwin )
{
if ( wwin -> icon == NULL )
return ;
if ( wwin -> flags . miniaturized && wwin -> icon -> mapped ) {
XUnmapWindow ( dpy , wwin -> icon -> core -> window );
RemoveFromStackList ( wwin -> icon -> core );
wIconDestroy ( wwin -> icon );
wwin -> icon = NULL ;
}
}
static Bool
handleWindowType ( WWindow * wwin , Atom type , int * layer )
{
Bool ret = True ;
if ( type == net_wm_window_type_desktop ) {
wwin -> client_flags . no_titlebar = 1 ;
wwin -> client_flags . no_resizable = 1 ;
wwin -> client_flags . no_miniaturizable = 1 ;
wwin -> client_flags . no_border = 1 ;
wwin -> client_flags . no_resizebar = 1 ;
wwin -> client_flags . no_shadeable = 1 ;
wwin -> client_flags . no_movable = 1 ;
wwin -> client_flags . omnipresent = 1 ;
wwin -> client_flags . skip_window_list = 1 ;
wwin -> client_flags . dont_move_off = 1 ;
wwin -> client_flags . no_appicon = 1 ;
wwin -> flags . net_skip_pager = 1 ;
wwin -> frame_x = 0 ;
wwin -> frame_y = 0 ;
#ifdef VIRTUAL_DESKTOP
wwin -> client_flags . virtual_stick = 1 ;
#endif
} else if ( type == net_wm_window_type_dock ) {
wwin -> client_flags . no_titlebar = 1 ;
wwin -> client_flags . no_resizable = 1 ;
wwin -> client_flags . no_miniaturizable = 1 ;
wwin -> client_flags . no_border = 1 ; /* XXX: really not a single decoration. */
wwin -> client_flags . no_resizebar = 1 ;
wwin -> client_flags . no_shadeable = 1 ;
wwin -> client_flags . no_movable = 1 ;
wwin -> client_flags . omnipresent = 1 ;
wwin -> client_flags . skip_window_list = 1 ;
wwin -> client_flags . dont_move_off = 1 ;
wwin -> flags . net_skip_pager = 1 ;
#ifdef VIRTUAL_DESKTOP
wwin -> client_flags . virtual_stick = 1 ;
#endif
} else if ( type == net_wm_window_type_toolbar ) {
wwin -> client_flags . no_titlebar = 1 ;
wwin -> client_flags . no_resizable = 1 ;
wwin -> client_flags . no_miniaturizable = 1 ;
wwin -> client_flags . no_resizebar = 1 ;
wwin -> client_flags . no_shadeable = 1 ;
wwin -> client_flags . skip_window_list = 1 ;
wwin -> client_flags . dont_move_off = 1 ;
wwin -> client_flags . no_appicon = 1 ;
} else if ( type == net_wm_window_type_menu ) {
wwin -> client_flags . no_titlebar = 1 ;
wwin -> client_flags . no_resizable = 1 ;
wwin -> client_flags . no_miniaturizable = 1 ;
wwin -> client_flags . no_resizebar = 1 ;
wwin -> client_flags . no_shadeable = 1 ;
wwin -> client_flags . skip_window_list = 1 ;
wwin -> client_flags . dont_move_off = 1 ;
wwin -> client_flags . no_appicon = 1 ;
} else if ( type == net_wm_window_type_utility ) {
wwin -> client_flags . no_appicon = 1 ;
} else if ( type == net_wm_window_type_splash ) {
wwin -> client_flags . no_titlebar = 1 ;
wwin -> client_flags . no_resizable = 1 ;
wwin -> client_flags . no_miniaturizable = 1 ;
wwin -> client_flags . no_resizebar = 1 ;
wwin -> client_flags . no_shadeable = 1 ;
wwin -> client_flags . no_movable = 1 ;
wwin -> client_flags . skip_window_list = 1 ;
wwin -> client_flags . dont_move_off = 1 ;
wwin -> client_flags . no_appicon = 1 ;
wwin -> flags . net_skip_pager = 1 ;
} else if ( type == net_wm_window_type_dialog ) {
// wwin->client_flags.skip_window_list = 1;
// wwin->client_flags.no_appicon = 1;
} else if ( type == net_wm_window_type_normal ) {
} else {
ret = False ;
}
wwin -> type = type ;
* layer = getWindowLayer ( wwin );
return ret ;
}
void
wNETWMPositionSplash ( WWindow * wwin , int * x , int * y , int width , int height )
{
if ( wwin -> type == net_wm_window_type_splash ) {
WScreen * scr = wwin -> screen_ptr ;
WMRect rect = wGetRectForHead ( scr , wGetHeadForPointerLocation ( scr ));
* x = rect . pos . x + ( rect . size . width - width ) / 2 ;
* y = rect . pos . y + ( rect . size . height - height ) / 2 ;
}
}
static void
updateWindowType ( WWindow * wwin )
{
Atom type_ret ;
int fmt_ret ;
unsigned long nitems_ret ;
unsigned long bytes_after_ret ;
long * data = 0 ;
int layer ;
if ( XGetWindowProperty ( dpy , wwin -> client_win , net_wm_window_type , 0 , 1 ,
False , XA_ATOM , & type_ret , & fmt_ret , & nitems_ret ,
& bytes_after_ret , ( unsigned char ** ) & data ) == Success
&& data ) {
int i ;
Atom * type = ( Atom * ) data ;
for ( i = 0 ; i < nitems_ret ; ++ i ) {
if ( handleWindowType ( wwin , type [ i ], & layer )) break ;
}
XFree ( data );
}
ChangeStackingLevel ( wwin -> frame -> core , layer );
wwin -> frame -> flags . need_texture_change = 1 ;
wWindowConfigureBorders ( wwin );
wFrameWindowPaint ( wwin -> frame );
wNETWMUpdateActions ( wwin , False );
}
Bool
wNETWMCheckClientHints ( WWindow * wwin , int * layer , int * workspace )
{
Atom type_ret ;
int fmt_ret ;
unsigned long nitems_ret ;
unsigned long bytes_after_ret ;
long * data = 0 ;
Bool hasState = False ;
int i ;
if ( XGetWindowProperty ( dpy , wwin -> client_win , net_wm_desktop , 0 , 1 , False ,
XA_CARDINAL , & type_ret , & fmt_ret , & nitems_ret ,
& bytes_after_ret ,
( unsigned char ** ) & data ) == Success && data ) {
long desktop = * data ;
XFree ( data );
if ( desktop == - 1 )
wwin -> client_flags . omnipresent = 1 ;
else
* workspace = desktop ;
hasState = True ;
}
if ( XGetWindowProperty ( dpy , wwin -> client_win , net_wm_state , 0 , 1 , False ,
XA_ATOM , & type_ret , & fmt_ret , & nitems_ret ,
& bytes_after_ret ,
( unsigned char ** ) & data ) == Success && data ) {
Atom * state = ( Atom * ) data ;
for ( i = 0 ; i < nitems_ret ; ++ i ) {
doStateAtom ( wwin , state [ i ], _NET_WM_STATE_ADD , True );
}
XFree ( data );
hasState = True ;
}
if ( XGetWindowProperty ( dpy , wwin -> client_win , net_wm_window_type , 0 , 1 , False ,
XA_ATOM , & type_ret , & fmt_ret , & nitems_ret ,
& bytes_after_ret ,
( unsigned char ** ) & data ) == Success && data ) {
Atom * type = ( Atom * ) data ;
for ( i = 0 ; i < nitems_ret ; ++ i ) {
if ( handleWindowType ( wwin , type [ i ], layer )) break ;
}
XFree ( data );
hasState = True ;
}
wNETWMUpdateActions ( wwin , False );
updateStrut ( wwin , False );
if ( updateStrut ( wwin , True )) {
hasState = True ;
}
wScreenUpdateUsableArea ( wwin -> screen_ptr );
return hasState ;
}
static Bool
updateNetIconInfo ( WWindow * wwin ) {
Atom type_ret ;
int fmt_ret ;
unsigned long nitems_ret ;
unsigned long bytes_after_ret ;
long * data = 0 ;
Bool hasState = False ;
Bool old_state = wwin -> flags . net_handle_icon ;
if ( XGetWindowProperty ( dpy , wwin -> client_win , net_wm_handled_icons , 0 , 1 , False ,
XA_CARDINAL , & type_ret , & fmt_ret , & nitems_ret ,
& bytes_after_ret , ( unsigned char ** ) & data ) == Success && data ) {
long handled = * data ;
wwin -> flags . net_handle_icon = ( handled != 0 );
XFree ( data );
hasState = True ;
} else wwin -> flags . net_handle_icon = False ;
if ( XGetWindowProperty ( dpy , wwin -> client_win , net_wm_icon_geometry , 0 , 4 , False ,
XA_CARDINAL , & type_ret , & fmt_ret , & nitems_ret ,
& bytes_after_ret , ( unsigned char ** ) & data ) == Success && data ) {
#ifdef NETWM_PROPER
if ( wwin -> flags . net_handle_icon )
#else
wwin -> flags . net_handle_icon = True ;
#endif
{
wwin -> icon_x = data [ 0 ];
wwin -> icon_y = data [ 1 ];
wwin -> icon_w = data [ 2 ];
wwin -> icon_h = data [ 3 ];
}
XFree ( data );
hasState = True ;
} else wwin -> flags . net_handle_icon = False ;
if ( wwin -> flags . miniaturized &&
old_state != wwin -> flags . net_handle_icon ) {
if ( wwin -> flags . net_handle_icon ) {
removeIcon ( wwin );
} else {
wwin -> flags . miniaturized = False ;
wwin -> flags . skip_next_animation = True ;
wIconifyWindow ( wwin );
}
}
return hasState ;
}
Bool
wNETWMCheckInitialClientState ( WWindow * wwin )
{
Bool hasState = False ;
#ifdef DEBUG_WMSPEC
printf ( "CheckInitialClientState \n " );
#endif
wNETWMShowingDesktop ( wwin -> screen_ptr , False );
hasState |= updateNetIconInfo ( wwin );
updateIconImage ( wwin -> screen_ptr , wwin );
return hasState ;
}
static void
handleDesktopNames ( XClientMessageEvent * event , WScreen * scr )
{
unsigned long nitems_ret , bytes_after_ret ;
char * data , * names [ 32 ];
int fmt_ret , i , n ;
Atom type_ret ;
if ( XGetWindowProperty ( dpy , scr -> root_win , net_desktop_names , 0 , 1 , False ,
utf8_string , & type_ret , & fmt_ret , & nitems_ret ,
& bytes_after_ret ,
( unsigned char ** ) & data ) != Success ) {
return ;
}
if ( data == 0 )
return ;
if ( type_ret != utf8_string || fmt_ret != 8 )
return ;
n = 0 ;
names [ n ] = data ;
for ( i = 0 ; i < nitems_ret ; i ++ ) {
if ( data [ i ] == 0 ) {
n ++ ;
names [ n ] = & data [ i ];
} else if ( * names [ n ] == 0 ) {
names [ n ] = & data [ i ];
wWorkspaceRename ( scr , n , names [ n ]);
}
}
}
Bool
wNETWMProcessClientMessage ( XClientMessageEvent * event )
{
WScreen * scr ;
WWindow * wwin ;
Bool done = True ;
#ifdef DEBUG_WMSPEC
printf ( "processClientMessage type %s \n " , XGetAtomName ( dpy , event -> message_type ));
#endif
scr = wScreenForWindow ( event -> window );
if ( scr ) {
/* generic client messages */
if ( event -> message_type == net_current_desktop ) {
wWorkspaceChange ( scr , event -> data . l [ 0 ]);
} else if ( event -> message_type == net_number_of_desktops ) {
long value ;
value = event -> data . l [ 0 ];
if ( value > scr -> workspace_count ) {
wWorkspaceMake ( scr , value - scr -> workspace_count );
} else if ( value < scr -> workspace_count ) {
int i ;
Bool rebuild = False ;
for ( i = scr -> workspace_count - 1 ; i >= value ; i -- ) {
if ( ! wWorkspaceDelete ( scr , i )) {
rebuild = True ;
break ;
}
}
if ( rebuild ) {
updateWorkspaceCount ( scr );
}
}
} else if ( event -> message_type == net_showing_desktop ) {
wNETWMShowingDesktop ( scr , event -> data . l [ 0 ]);
#ifdef VIRTUAL_DESKTOP
} else if ( event -> message_type == net_desktop_viewport ) {
wWorkspaceSetViewPort ( scr , scr -> current_workspace ,
event -> data . l [ 0 ], event -> data . l [ 1 ]);
#endif
} else if ( event -> message_type == net_desktop_names ) {
handleDesktopNames ( event , scr );
} else {
done = False ;
}
if ( done )
return True ;
}
/* window specific client messages */
wwin = wWindowFor ( event -> window );
if ( ! wwin )
return False ;
if ( event -> message_type == net_active_window ) {
wNETWMShowingDesktop ( scr , False );
wMakeWindowVisible ( wwin );
} else if ( event -> message_type == net_close_window ) {
if ( ! WFLAGP ( wwin , no_closable )) {
if ( wwin -> protocols . DELETE_WINDOW )
wClientSendProtocol ( wwin , _XA_WM_DELETE_WINDOW , LastTimestamp );
}
} else if ( event -> message_type == net_wm_state ) {
int maximized = wwin -> flags . maximized ;
long set = event -> data . l [ 0 ];
#ifdef DEBUG_WMSPEC
printf ( "net_wm_state set %d a1 %s a2 %s \n " , set ,
XGetAtomName ( dpy , event -> data . l [ 1 ]),
XGetAtomName ( dpy , event -> data . l [ 2 ]));
#endif
doStateAtom ( wwin , ( Atom ) event -> data . l [ 1 ], set , False );
if ( event -> data . l [ 2 ])
doStateAtom ( wwin , ( Atom ) event -> data . l [ 2 ], set , False );
if ( wwin -> flags . maximized != maximized ) {
if ( ! wwin -> flags . maximized ) {
wwin -> flags . maximized = maximized ;
wUnmaximizeWindow ( wwin );
} else {
wMaximizeWindow ( wwin , wwin -> flags . maximized );
}
}
updateStateHint ( wwin , False , False );
} else if ( event -> message_type == net_wm_handled_icons ||
event -> message_type == net_wm_icon_geometry ) {
updateNetIconInfo ( wwin );
} else if ( event -> message_type == net_wm_desktop ) {
long desktop = event -> data . l [ 0 ];
if ( desktop == - 1 ) {
wWindowSetOmnipresent ( wwin , True );
} else {
if ( IS_OMNIPRESENT ( wwin ))
wWindowSetOmnipresent ( wwin , False );
wWindowChangeWorkspace ( wwin , desktop );
}
} else if ( event -> message_type == net_wm_icon ) {
updateIconImage ( scr , wwin );
} else {
done = False ;
}
return done ;
}
Bool
wNETWMCheckClientHintChange ( WWindow * wwin , XPropertyEvent * event )
{
Bool ret = True ;
if ( event -> atom == net_wm_strut ) {
updateStrut ( wwin , False );
updateStrut ( wwin , True );
wScreenUpdateUsableArea ( wwin -> screen_ptr );
} else if ( event -> atom == net_wm_handled_icons ||
event -> atom == net_wm_icon_geometry ) {
updateNetIconInfo ( wwin );
} else if ( event -> atom == net_wm_window_type ) {
updateWindowType ( wwin );
} else {
ret = False ;
}
return ret ;
}
int
wNETWMGetPidForWindow ( Window window )
{
Atom type_ret ;
int fmt_ret ;
unsigned long nitems_ret ;
unsigned long bytes_after_ret ;
long * data = 0 ;
int pid ;
if ( XGetWindowProperty ( dpy , window , net_wm_pid , 0 , 1 , False ,
XA_CARDINAL , & type_ret , & fmt_ret , & nitems_ret ,
& bytes_after_ret ,
( unsigned char ** ) & data ) == Success && data ) {
pid = * data ;
XFree ( data );
} else {
pid = 0 ;
}
return pid ;
}
2001-09-12 21:43:42 +00:00
static void
observer ( void * self , WMNotification * notif )
{
WWindow * wwin = ( WWindow * ) WMGetNotificationObject ( notif );
const char * name = WMGetNotificationName ( notif );
void * data = WMGetNotificationClientData ( notif );
NetData * ndata = ( NetData * ) self ;
2004-10-12 01:34:32 +00:00
2001-09-12 21:43:42 +00:00
if ( strcmp ( name , WMNManaged ) == 0 && wwin ) {
2004-10-12 01:34:32 +00:00
updateClientList ( wwin -> screen_ptr );
updateClientListStacking ( wwin -> screen_ptr , NULL );
updateStateHint ( wwin , True , False );
2001-09-12 21:43:42 +00:00
2004-10-12 01:34:32 +00:00
updateStrut ( wwin , False );
updateStrut ( wwin , True );
wScreenUpdateUsableArea ( wwin -> screen_ptr );
2001-09-12 21:43:42 +00:00
} else if ( strcmp ( name , WMNUnmanaged ) == 0 && wwin ) {
2004-10-12 01:34:32 +00:00
updateClientList ( wwin -> screen_ptr );
updateClientListStacking ( wwin -> screen_ptr , wwin );
updateWorkspaceHint ( wwin , False , True );
updateStateHint ( wwin , False , True );
wNETWMUpdateActions ( wwin , True );
updateStrut ( wwin , False );
wScreenUpdateUsableArea ( wwin -> screen_ptr );
2001-09-12 21:43:42 +00:00
} else if ( strcmp ( name , WMNResetStacking ) == 0 && wwin ) {
2004-10-12 01:34:32 +00:00
updateClientListStacking ( wwin -> screen_ptr , NULL );
updateStateHint ( wwin , False , False );
2001-09-12 21:43:42 +00:00
} else if ( strcmp ( name , WMNChangedStacking ) == 0 && wwin ) {
2004-10-12 01:34:32 +00:00
updateClientListStacking ( wwin -> screen_ptr , NULL );
updateStateHint ( wwin , False , False );
2001-09-12 21:43:42 +00:00
} else if ( strcmp ( name , WMNChangedFocus ) == 0 ) {
2004-10-12 01:34:32 +00:00
updateFocusHint ( ndata -> scr , wwin );
2001-09-12 21:43:42 +00:00
} else if ( strcmp ( name , WMNChangedWorkspace ) == 0 && wwin ) {
2004-10-12 01:34:32 +00:00
updateWorkspaceHint ( wwin , False , False );
updateStateHint ( wwin , True , False );
2001-09-12 21:43:42 +00:00
} else if ( strcmp ( name , WMNChangedState ) == 0 && wwin ) {
2004-10-12 01:34:32 +00:00
updateStateHint ( wwin , ! strcmp ( data , "omnipresent" ), False );
2001-09-12 21:43:42 +00:00
}
}
static void
wsobserver ( void * self , WMNotification * notif )
{
WScreen * scr = ( WScreen * ) WMGetNotificationObject ( notif );
const char * name = WMGetNotificationName ( notif );
2004-10-12 01:34:32 +00:00
//void *data = WMGetNotificationClientData(notif);
2001-09-12 21:43:42 +00:00
if ( strcmp ( name , WMNWorkspaceCreated ) == 0 ) {
2004-10-12 01:34:32 +00:00
updateWorkspaceCount ( scr );
updateWorkspaceNames ( scr );
2001-09-12 21:43:42 +00:00
} else if ( strcmp ( name , WMNWorkspaceDestroyed ) == 0 ) {
2004-10-12 01:34:32 +00:00
updateWorkspaceCount ( scr );
updateWorkspaceNames ( scr );
2001-09-12 21:43:42 +00:00
} else if ( strcmp ( name , WMNWorkspaceChanged ) == 0 ) {
2004-10-12 01:34:32 +00:00
updateCurrentWorkspace ( scr );
2001-09-12 21:43:42 +00:00
} else if ( strcmp ( name , WMNWorkspaceNameChanged ) == 0 ) {
2004-10-12 01:34:32 +00:00
updateWorkspaceNames ( scr );
2001-09-12 21:43:42 +00:00
}
}
2004-10-12 01:34:32 +00:00
#endif /* NETWM_HINTS */
2001-09-12 21:43:42 +00:00