2 * ion/mod_sm/sm_mathcwin.c
4 * Copyright (c) Tuomo Valkonen 2004-2006.
6 * Based on the code of the 'sm' module for Ion1 by an unknown contributor.
8 * Ion 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);