- s/sprintf/snprintf
[wmaker-crm.git] / src / switchmenu.c
blob52af50b5a3e062ff94ce521ce145f7a3e2cf87b4
1 /*
2 * Window Maker window manager
3 *
4 * Copyright (c) 1997 Shige Abe and
5 * Alfredo K. Kojima
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 * USA.
24 #include "wconfig.h"
26 #ifndef LITE
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xutil.h>
35 #include "WindowMaker.h"
36 #include "window.h"
37 #include "actions.h"
38 #include "client.h"
39 #include "funcs.h"
40 #include "stacking.h"
41 #include "workspace.h"
42 #include "framewin.h"
44 /********* Global Variables *******/
45 extern WPreferences wPreferences;
46 extern Time LastTimestamp;
50 * FocusWindow
52 * - Needs to check if already in the right workspace before
53 * calling wChangeWorkspace?
55 * Order:
56 * Switch to correct workspace
57 * Unshade if shaded
58 * If iconified then deiconify else focus/raise.
60 static void
61 focusWindow(WMenu *menu, WMenuEntry *entry)
63 WWindow *wwin;
64 WScreen *scr;
65 int x, y, move=0;
67 wwin = (WWindow*)entry->clientdata;
68 scr = wwin->screen_ptr;
70 wMakeWindowVisible(wwin);
72 x = wwin->frame_x;
73 y = wwin->frame_y;
75 /* bring window back to visible area */
76 move = wScreenBringInside(scr, &x, &y, wwin->frame->core->width,
77 wwin->frame->core->height);
79 if (move) {
80 wWindowConfigure(wwin, x, y, wwin->client.width, wwin->client.height);
86 * Open switch menu
89 void
90 OpenSwitchMenu(WScreen *scr, int x, int y, int keyboard)
92 WMenu *switchmenu = scr->switch_menu;
93 WWindow *wwin;
95 if (switchmenu) {
96 if (switchmenu->flags.mapped) {
97 if (!switchmenu->flags.buttoned) {
98 wMenuUnmap(switchmenu);
99 } else {
100 wRaiseFrame(switchmenu->frame->core);
102 if (keyboard)
103 wMenuMapAt(switchmenu, 0, 0, True);
104 else
105 wMenuMapCopyAt(switchmenu,
106 x-switchmenu->frame->core->width/2, y);
108 } else {
109 wMenuMapAt(switchmenu, x-switchmenu->frame->core->width/2, y,
110 keyboard);
112 return;
114 switchmenu = wMenuCreate(scr,_("Windows"),True);
115 scr->switch_menu = switchmenu;
118 wwin = scr->focused_window;
119 while (wwin) {
120 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
122 wwin = wwin->prev;
125 if (switchmenu) {
126 int newx, newy;
128 if (!switchmenu->flags.realized)
129 wMenuRealize(switchmenu);
131 if (keyboard && x==0 && y==0) {
132 newx = newy = 0;
133 } else if (keyboard && x==scr->scr_width/2 && y==scr->scr_height/2) {
134 newx = x - switchmenu->frame->core->width/2;
135 newy = y - switchmenu->frame->core->height/2;
136 } else {
137 newx = x - switchmenu->frame->core->width/2;
138 newy = y;
140 wMenuMapAt(switchmenu, newx, newy, keyboard);
145 static int
146 menuIndexForWindow(WMenu *menu, WWindow *wwin, int old_pos)
148 int idx;
150 if (menu->entry_no == 0)
151 return -1;
153 #define WS(i) ((WWindow*)menu->entries[i]->clientdata)->frame->workspace
154 if (old_pos >= 0) {
155 if (WS(old_pos) >= wwin->frame->workspace
156 && (old_pos == 0 || WS(old_pos-1) <= wwin->frame->workspace)) {
157 return old_pos;
160 #undef WS
162 for (idx = 0; idx < menu->entry_no; idx++) {
163 WWindow *tw = (WWindow*)menu->entries[idx]->clientdata;
165 if (!IS_OMNIPRESENT(tw)
166 && tw->frame->workspace > wwin->frame->workspace) {
167 break;
171 return idx;
176 * Update switch menu
178 void
179 UpdateSwitchMenu(WScreen *scr, WWindow *wwin, int action)
181 WMenu *switchmenu = scr->switch_menu;
182 WMenuEntry *entry;
183 char title[MAX_MENU_TEXT_LENGTH+6];
184 int len = MAX_MENU_TEXT_LENGTH+6;
185 int i;
186 int checkVisibility = 0;
188 if (!wwin->screen_ptr->switch_menu)
189 return;
191 * This menu is updated under the following conditions:
193 * 1. When a window is created.
194 * 2. When a window is destroyed.
196 * 3. When a window changes it's title.
197 * 4. When a window changes its workspace.
199 if (action == ACTION_ADD) {
200 char *t;
201 int idx;
203 if (wwin->flags.internal_window || WFLAGP(wwin, skip_window_list))
204 return;
206 if (wwin->frame->title)
207 snprintf(title, len, "%s", wwin->frame->title);
208 else
209 snprintf(title, len, "%s", DEF_WINDOW_TITLE);
210 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
212 if (IS_OMNIPRESENT(wwin))
213 idx = -1;
214 else {
215 idx = menuIndexForWindow(switchmenu, wwin, -1);
218 entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
219 wfree(t);
221 entry->flags.indicator = 1;
222 entry->rtext = wmalloc(MAX_WORKSPACENAME_WIDTH+8);
223 if (IS_OMNIPRESENT(wwin))
224 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
225 else
226 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
227 scr->workspaces[wwin->frame->workspace]->name);
229 if (wwin->flags.hidden) {
230 entry->flags.indicator_type = MI_HIDDEN;
231 entry->flags.indicator_on = 1;
232 } else if (wwin->flags.miniaturized) {
233 entry->flags.indicator_type = MI_MINIWINDOW;
234 entry->flags.indicator_on = 1;
235 } else if (wwin->flags.focused) {
236 entry->flags.indicator_type = MI_DIAMOND;
237 entry->flags.indicator_on = 1;
238 } else if (wwin->flags.shaded) {
239 entry->flags.indicator_type = MI_SHADED;
240 entry->flags.indicator_on = 1;
243 wMenuRealize(switchmenu);
244 checkVisibility = 1;
245 } else {
246 char *t;
247 for (i=0; i<switchmenu->entry_no; i++) {
248 entry = switchmenu->entries[i];
249 /* this is the entry that was changed */
250 if (entry->clientdata == wwin) {
251 switch (action) {
252 case ACTION_REMOVE:
253 wMenuRemoveItem(switchmenu, i);
254 wMenuRealize(switchmenu);
255 checkVisibility = 1;
256 break;
258 case ACTION_CHANGE:
259 if (entry->text)
260 wfree(entry->text);
262 if (wwin->frame->title)
263 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s",
264 wwin->frame->title);
265 else
266 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s",
267 DEF_WINDOW_TITLE);
269 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
270 entry->text = t;
272 wMenuRealize(switchmenu);
273 checkVisibility = 1;
274 break;
276 case ACTION_CHANGE_WORKSPACE:
277 if (entry->rtext) {
278 int idx = -1;
279 char *t, *rt;
280 int it, ion;
282 if (IS_OMNIPRESENT(wwin)) {
283 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH,
284 "[*]");
285 } else {
286 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH,
287 "[%s]", scr->workspaces[wwin->frame->workspace]->name);
290 rt = entry->rtext;
291 entry->rtext = NULL;
292 t = entry->text;
293 entry->text = NULL;
295 it = entry->flags.indicator_type;
296 ion = entry->flags.indicator_on;
298 wMenuRemoveItem(switchmenu, i);
300 if (!IS_OMNIPRESENT(wwin) && idx < 0) {
301 idx = menuIndexForWindow(switchmenu, wwin, i);
304 entry = wMenuInsertCallback(switchmenu, idx, t,
305 focusWindow, wwin);
306 wfree(t);
307 entry->rtext = rt;
308 entry->flags.indicator = 1;
309 entry->flags.indicator_type = it;
310 entry->flags.indicator_on = ion;
312 wMenuRealize(switchmenu);
313 checkVisibility = 1;
314 break;
317 case ACTION_CHANGE_STATE:
318 if (wwin->flags.hidden) {
319 entry->flags.indicator_type = MI_HIDDEN;
320 entry->flags.indicator_on = 1;
321 } else if (wwin->flags.miniaturized) {
322 entry->flags.indicator_type = MI_MINIWINDOW;
323 entry->flags.indicator_on = 1;
324 } else if (wwin->flags.shaded && !wwin->flags.focused) {
325 entry->flags.indicator_type = MI_SHADED;
326 entry->flags.indicator_on = 1;
327 } else {
328 entry->flags.indicator_on = wwin->flags.focused;
329 entry->flags.indicator_type = MI_DIAMOND;
331 break;
333 break;
337 if (checkVisibility) {
338 int tmp;
340 tmp = switchmenu->frame->top_width + 5;
341 /* if menu got unreachable, bring it to a visible place */
342 if (switchmenu->frame_x < tmp - (int)switchmenu->frame->core->width) {
343 wMenuMove(switchmenu, tmp - (int)switchmenu->frame->core->width,
344 switchmenu->frame_y, False);
347 wMenuPaint(switchmenu);
352 void
353 UpdateSwitchMenuWorkspace(WScreen *scr, int workspace)
355 WMenu *menu = scr->switch_menu;
356 int i;
357 WWindow *wwin;
359 if (!menu)
360 return;
362 for (i=0; i<menu->entry_no; i++) {
363 wwin = (WWindow*)menu->entries[i]->clientdata;
365 if (wwin->frame->workspace==workspace
366 && !IS_OMNIPRESENT(wwin)) {
367 if (IS_OMNIPRESENT(wwin))
368 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH,"[*]");
369 else
370 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH,"[%s]",
371 scr->workspaces[wwin->frame->workspace]->name);
372 menu->flags.realized = 0;
375 if (!menu->flags.realized)
376 wMenuRealize(menu);
380 #endif /* !LITE */