2 * ion/mod_sm/sm_mathcwin.c
4 * Copyright (c) Tuomo Valkonen 2004-2009.
6 * Based on the code of the 'sm' module for Ion1 by an unknown contributor.
8 * This is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
17 #include <X11/Xatom.h>
19 #include <libmainloop/signal.h>
20 #include <ioncore/common.h>
21 #include <ioncore/global.h>
22 #include <ioncore/exec.h>
23 #include <ioncore/names.h>
24 #include <ioncore/property.h>
26 #include "sm_matchwin.h"
28 #define TIME_OUT 60000
30 static WWinMatch
*match_list
=NULL
;
31 static WTimer
*purge_timer
=NULL
;
34 char *mod_sm_get_window_role(Window window
)
39 atom
=XInternAtom(ioncore_g
.dpy
, "WM_WINDOW_ROLE", False
);
41 if(XGetTextProperty(ioncore_g
.dpy
, window
, &tp
, atom
))
43 if(tp
.encoding
== XA_STRING
&& tp
.format
== 8 && tp
.nitems
!= 0)
44 return((char *)tp
.value
);
50 Window
mod_sm_get_client_leader(Window window
)
52 Window client_leader
= 0;
57 unsigned long bytes_after
;
58 unsigned char *prop
= NULL
;
60 atom
=XInternAtom(ioncore_g
.dpy
, "WM_CLIENT_LEADER", False
);
62 if(XGetWindowProperty(ioncore_g
.dpy
, window
, atom
,
63 0L, 1L, False
, AnyPropertyType
, &actual_type
,
64 &actual_format
, &nitems
, &bytes_after
,
67 if(actual_type
== XA_WINDOW
&& actual_format
== 32
68 && nitems
== 1 && bytes_after
== 0)
69 client_leader
=*((Window
*)prop
);
75 char *mod_sm_get_client_id(Window window
)
77 char *client_id
= NULL
;
82 if((client_leader
=mod_sm_get_client_leader(window
))!=0){
83 atom
=XInternAtom(ioncore_g
.dpy
, "SM_CLIENT_ID", False
);
84 if (XGetTextProperty (ioncore_g
.dpy
, client_leader
, &tp
, atom
))
85 if (tp
.encoding
== XA_STRING
&& tp
.format
== 8 && tp
.nitems
!= 0)
86 client_id
= (char *) tp
.value
;
92 char *mod_sm_get_window_cmd(Window window
)
94 char **cmd_argv
, *command
=NULL
;
95 int id
, i
, len
=0, cmd_argc
=0;
97 if(XGetCommand(ioncore_g
.dpy
, window
, &cmd_argv
, &cmd_argc
) && (cmd_argc
> 0))
99 else if((id
=mod_sm_get_client_leader(window
)))
100 XGetCommand(ioncore_g
.dpy
, id
, &cmd_argv
, &cmd_argc
);
103 for(i
=0; i
< cmd_argc
; i
++)
104 len
+=strlen(cmd_argv
[i
])+1;
105 command
=ALLOC_N(char, len
+1);
106 strcpy(command
, cmd_argv
[0]);
107 for(i
=1; i
< cmd_argc
; i
++){
108 strcat(command
, " ");
109 strcat(command
, cmd_argv
[i
]);
111 XFreeStringList(cmd_argv
);
117 static void free_win_match(WWinMatch
*match
)
119 UNLINK_ITEM(match_list
, match
, next
, prev
);
121 if(match
->pholder
!=NULL
)
122 destroy_obj((Obj
*)match
->pholder
);
125 free(match
->client_id
);
126 if(match
->window_role
)
127 free(match
->window_role
);
131 free(match
->wm_name
);
137 static void mod_sm_purge_matches(WTimer
*timer
)
139 assert(timer
==purge_timer
);
141 destroy_obj((Obj
*)timer
);
144 warn("purging remaining matches\n");
147 free_win_match(match_list
);
150 void mod_sm_start_purge_timer()
152 if(purge_timer
==NULL
)
153 purge_timer
=create_timer();
154 if(purge_timer
!=NULL
){
155 timer_set(purge_timer
, TIME_OUT
,
156 (WTimerHandler
*)mod_sm_purge_matches
, NULL
);
160 void mod_sm_register_win_match(WWinMatch
*match
)
162 LINK_ITEM(match_list
, match
, next
, prev
);
165 bool mod_sm_have_match_list()
173 #define xstreq(a,b) (a && b && (strcmp(a,b)==0))
175 /* Tries to match a window against a list of loaded matches */
177 static WWinMatch
*match_cwin(WClientWin
*cwin
)
179 WWinMatch
*match
=match_list
;
182 char *client_id
=mod_sm_get_client_id(cwin
->win
);
183 char *window_role
=mod_sm_get_window_role(cwin
->win
);
184 char *wm_cmd
=mod_sm_get_window_cmd(cwin
->win
);
188 wm_name
=xwindow_get_text_property(cwin
->win
, XA_WM_NAME
, &n
);
190 assert(wm_name
==NULL
);
192 XGetClassHint(ioncore_g
.dpy
, cwin
->win
, &clss
);
194 for(; match
!=NULL
; match
=match
->next
){
198 if(client_id
|| match
->client_id
){
199 if(xstreq(match
->client_id
, client_id
)){
201 if(xstreq(match
->window_role
, window_role
))
206 if(xstreq(match
->wclass
, clss
.res_class
) && xstreq(match
->winstance
, clss
.res_name
)){
209 if(xstreq(match
->wm_cmd
, wm_cmd
))
211 if(wm_name
!=NULL
&& *wm_name
!=NULL
&&
212 xstreq(match
->wm_name
, *wm_name
)){
223 XFreeStringList(wm_name
);
228 /* Returns frame_id of a match. Called from add_clientwin_alt in sm.c */
230 WPHolder
*mod_sm_match_cwin_to_saved(WClientWin
*cwin
)
232 WWinMatch
*match
=NULL
;
235 if((match
=match_cwin(cwin
))){
238 free_win_match(match
);
245 bool mod_sm_add_match(WPHolder
*ph
, ExtlTab tab
)
260 extl_table_gets_s(tab
, "mod_sm_client_id", &(m
->client_id
));
261 extl_table_gets_s(tab
, "mod_sm_window_role", &(m
->window_role
));
262 extl_table_gets_s(tab
, "mod_sm_wclass", &(m
->wclass
));
263 extl_table_gets_s(tab
, "mod_sm_winstance", &(m
->winstance
));
264 extl_table_gets_s(tab
, "mod_sm_wm_name", &(m
->wm_name
));
265 extl_table_gets_s(tab
, "mod_sm_wm_cmd", &(m
->wm_cmd
));
269 mod_sm_register_win_match(m
);
275 void mod_sm_get_configuration(WClientWin
*cwin
, ExtlTab tab
)
278 char *client_id
=NULL
, *window_role
=NULL
, *wm_cmd
=NULL
, **wm_name
;
281 if((client_id
=mod_sm_get_client_id(cwin
->win
))){
282 extl_table_sets_s(tab
, "mod_sm_client_id", client_id
);
287 if((window_role
=mod_sm_get_window_role(cwin
->win
))){
288 extl_table_sets_s(tab
, "mod_sm_window_role", window_role
);
292 if(XGetClassHint(ioncore_g
.dpy
, cwin
->win
, &clss
) != 0){
293 extl_table_sets_s(tab
, "mod_sm_wclass", clss
.res_class
);
294 extl_table_sets_s(tab
, "mod_sm_winstance", clss
.res_name
);
297 wm_name
=xwindow_get_text_property(cwin
->win
, XA_WM_NAME
, &n
);
299 if(n
>0 && wm_name
!=NULL
){
300 extl_table_sets_s(tab
, "mod_sm_wm_name", *wm_name
);
301 XFreeStringList(wm_name
);
305 if((wm_cmd
=mod_sm_get_window_cmd(cwin
->win
))){
306 extl_table_sets_s(tab
, "mod_sm_wm_cmd", wm_cmd
);