1 /*
2 * Copyright (c) 2000 Sasha Vasko <sasha at aftercode.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 */
19
20 #define LOCAL_DEBUG
21
22 #include "../configure.h"
23 #include "asapp.h"
24 #include <X11/cursorfont.h>
25
26
27 #include "afterstep.h"
28 #include "screen.h"
29 #include "asfeel.h"
30 #include "event.h"
31
32 /**************************************************************************************
33 * ASFeel initialization and destruction code.
34 *************************************************************************************/
35
init_asfeel(ASFeel * feel)36 void init_asfeel (ASFeel * feel)
37 {
38 int i;
39
40 memset (feel, 0x00, sizeof (ASFeel));
41 feel->magic = MAGIC_ASFEEL;
42 feel->buttons2grab = 7;
43 feel->AutoReverse = 0;
44 feel->Xzap = 12;
45 feel->Yzap = 12;
46 feel->EdgeScrollX = feel->EdgeScrollY = -100000;
47 feel->EdgeResistanceScroll = 0;
48 feel->EdgeResistanceMove = 30;
49 feel->EdgeAttractionScreen = 20;
50 feel->EdgeAttractionWindow = 10;
51 feel->EdgeResistanceDragScroll = -1; /* by default should use EdgeResistanceScroll */
52 feel->OpaqueMove = 5;
53 feel->OpaqueResize = 5;
54 feel->ClickTime = 500; /* half a sec, for those sluggish folks */
55 feel->AutoRaiseDelay = 0;
56 feel->RaiseButtons = 0;
57 #ifdef __CYGWIN__
58 feel->flags = DoHandlePageing;
59 #else
60 feel->flags = DoHandlePageing /*|DontAnimateBackground */ ;
61 #endif
62 feel->XorValue = (((unsigned long)1) << ASDefaultScr->d_depth) - 1;
63
64 feel->no_snaping_mod = ShiftMask | ControlMask;
65
66 feel->MouseButtonRoot = NULL;
67 feel->FuncKeyRoot = NULL;
68 feel->Popups = NULL;
69 feel->ComplexFunctions = NULL;
70 feel->ShadeAnimationSteps = 12;
71
72 feel->desk_cover_animation_type = 10;
73 feel->desk_cover_animation_steps = 12;
74
75 feel->recent_submenu_items = 4;
76
77 for (i = 0; i < MAX_CURSORS; ++i)
78 if (feel->cursors[i])
79 feel->cursors[i] = ASDefaultScr->standard_cursors[i];
80 }
81
create_asfeel()82 ASFeel *create_asfeel ()
83 {
84 ASFeel *feel;
85
86 feel = safecalloc (1, sizeof (ASFeel));
87 init_asfeel (feel);
88 return feel;
89 }
90
destroy_asfeel(ASFeel * feel,Bool reusable)91 void destroy_asfeel (ASFeel * feel, Bool reusable)
92 {
93 if (feel) {
94 if (feel->magic == MAGIC_ASFEEL) {
95 register int i;
96
97 feel->magic = 0;
98
99 while (feel->MouseButtonRoot != NULL) {
100 MouseButton *mb = feel->MouseButtonRoot;
101
102 feel->MouseButtonRoot = mb->NextButton;
103 if (mb->fdata) {
104 free_func_data (mb->fdata);
105 free (mb->fdata);
106 }
107 free (mb);
108 }
109 while (feel->FuncKeyRoot != NULL) {
110 FuncKey *fk = feel->FuncKeyRoot;
111
112 feel->FuncKeyRoot = fk->next;
113 if (fk->name != NULL)
114 free (fk->name);
115 if (fk->fdata != NULL) {
116 free_func_data (fk->fdata);
117 free (fk->fdata);
118 }
119 free (fk);
120 }
121 for (i = 0; i < MAX_CURSORS; ++i)
122 if (feel->cursors[i]
123 && feel->cursors[i] != ASDefaultScr->standard_cursors[i]) {
124 XFreeCursor (dpy, feel->cursors[i]);
125 feel->cursors[i] = None;
126 }
127 if (feel->Popups)
128 destroy_ashash (&feel->Popups);
129 if (feel->ComplexFunctions)
130 destroy_ashash (&feel->ComplexFunctions);
131 if (feel->window_boxes) {
132 i = feel->window_boxes_num;
133 while (--i >= 0)
134 destroy_aswindow_box (&(feel->window_boxes[i]), True);
135 free (feel->window_boxes);
136 }
137 destroy_string (&(feel->default_window_box_name));
138 }
139 if (!reusable)
140 free (feel);
141 else
142 memset (feel, 0x00, sizeof (ASFeel));
143 }
144 }
145
apply_feel_cursor(Window w,ASFeel * feel,int cursor)146 void apply_feel_cursor (Window w, ASFeel * feel, int cursor)
147 {
148 if (feel && cursor >= 0 && cursor < MAX_CURSORS && w != None)
149 XDefineCursor (dpy, w, feel->cursors[cursor]);
150 }
151
recolor_feel_cursors(ASFeel * feel,CARD32 fore,CARD32 back)152 void recolor_feel_cursors (ASFeel * feel, CARD32 fore, CARD32 back)
153 {
154 if (feel) {
155 int i;
156 XColor xfore, xback;
157
158 xfore.red = ARGB32_RED16 (fore);
159 xfore.green = ARGB32_GREEN16 (fore);
160 xfore.blue = ARGB32_BLUE16 (fore);
161 xback.red = ARGB32_RED16 (back);
162 xback.green = ARGB32_GREEN16 (back);
163 xback.blue = ARGB32_BLUE16 (back);
164 for (i = 0; i < MAX_CURSORS; ++i)
165 if (feel->cursors[i])
166 XRecolorCursor (dpy, feel->cursors[i], &xfore, &xback);
167 }
168 }
169
170
171
apply_context_cursor(Window w,ASFeel * feel,unsigned long context)172 void apply_context_cursor (Window w, ASFeel * feel, unsigned long context)
173 {
174 if (feel && context != 0 && w != None) {
175 static Cursor last_cursor = None;
176 static Window last_window = None;
177 Cursor c = None;
178
179 switch (context) {
180 case C_TITLE:
181 c = feel->cursors[ASCUR_Title];
182 break;
183 case C_FrameN:
184 c = feel->cursors[ASCUR_Top];
185 break;
186 case C_FrameE:
187 c = feel->cursors[ASCUR_Right];
188 break;
189 case C_FrameS:
190 c = feel->cursors[ASCUR_Bottom];
191 break;
192 case C_FrameW:
193 c = feel->cursors[ASCUR_Left];
194 break;
195 case C_FrameNW:
196 c = feel->cursors[ASCUR_TopLeft];
197 break;
198 case C_FrameNE:
199 c = feel->cursors[ASCUR_TopRight];
200 break;
201 case C_FrameSW:
202 c = feel->cursors[ASCUR_BottomLeft];
203 break;
204 case C_FrameSE:
205 c = feel->cursors[ASCUR_BottomRight];
206 break;
207 default:
208 if (get_flags (context, C_TButtonAll))
209 c = feel->cursors[ASCUR_Sys];
210 else if (get_flags (context, C_FRAME))
211 c = feel->cursors[ASCUR_Move];
212 }
213
214 if (c == None && get_flags (context, C_FRAME))
215 c = feel->cursors[ASCUR_Move];
216 LOCAL_DEBUG_OUT ("context %s, selected cursor %ld, window %lX",
217 context2text (context), c, w);
218 if (last_window != w || last_cursor != c) {
219 last_cursor = c;
220 last_window = w;
221 XDefineCursor (dpy, w, c);
222 }
223 }
224 }
225
free_feel_cursors(ASFeel * feel)226 void free_feel_cursors (ASFeel * feel)
227 {
228 register int i;
229
230 if (dpy == NULL || feel == NULL)
231 return;
232 /* free cursors */
233 for (i = 0; i < MAX_CURSORS; i++)
234 if (feel->cursors[i])
235 XFreeCursor (dpy, feel->cursors[i]);
236 }
237
check_feel_sanity(ASFeel * feel)238 void check_feel_sanity (ASFeel * feel)
239 {
240 int i;
241
242 LOCAL_DEBUG_CALLER_OUT ("feel %p", feel);
243 /* If no edge scroll line is provided in the setup file, use a default */
244 if (feel->EdgeScrollX == -100000)
245 feel->EdgeScrollX = 25;
246 if (feel->EdgeScrollY == -100000)
247 feel->EdgeScrollY = feel->EdgeScrollX;
248
249 if (get_flags (feel->flags, ClickToRaise) && (feel->AutoRaiseDelay == 0))
250 feel->AutoRaiseDelay = -1;
251
252 /* if edgescroll >1000 and < 100000m
253 * wrap at edges of desktop (a "spherical" desktop) */
254 feel->flags &= ~(EdgeWrapX | EdgeWrapY);
255 if (feel->EdgeScrollX >= 1000) {
256 feel->EdgeScrollX /= 1000;
257 feel->flags |= EdgeWrapX;
258 }
259 if (feel->EdgeScrollY >= 1000) {
260 feel->EdgeScrollY /= 1000;
261 feel->flags |= EdgeWrapY;
262 }
263
264 feel->EdgeScrollX =
265 feel->EdgeScrollX * ASDefaultScr->MyDisplayWidth / 100;
266 feel->EdgeScrollY =
267 feel->EdgeScrollY * ASDefaultScr->MyDisplayHeight / 100;
268
269 if (feel->no_snaping_mod == 0)
270 feel->no_snaping_mod = ShiftMask;
271
272 if (ASDefaultScr->VxMax == 0)
273 clear_flags (feel->flags, EdgeWrapX);
274 if (ASDefaultScr->VyMax == 0)
275 clear_flags (feel->flags, EdgeWrapY);
276
277 i = feel->window_boxes_num;
278 while (--i >= 0) {
279 if (!get_flags (feel->window_boxes[i].area.flags, WidthValue)) {
280 feel->window_boxes[i].area.width = ASDefaultScr->MyDisplayWidth;
281 if (get_flags (feel->window_boxes[i].flags, ASA_Virtual))
282 feel->window_boxes[i].area.width += ASDefaultScr->VxMax;
283 feel->window_boxes[i].area.width -= feel->window_boxes[i].area.x;
284 }
285 if (!get_flags (feel->window_boxes[i].area.flags, HeightValue)) {
286 feel->window_boxes[i].area.height = ASDefaultScr->MyDisplayHeight;
287 if (get_flags (feel->window_boxes[i].flags, ASA_Virtual))
288 feel->window_boxes[i].area.height += ASDefaultScr->VyMax;
289 feel->window_boxes[i].area.height -= feel->window_boxes[i].area.y;
290 }
291 if (!get_flags (feel->window_boxes[i].flags, ASA_DesktopSet))
292 feel->window_boxes[i].desk = INVALID_DESK;
293
294 if (!get_flags (feel->window_boxes[i].flags, ASA_MinLayerSet))
295 feel->window_boxes[i].min_layer = AS_LayerLowest;
296
297 if (!get_flags (feel->window_boxes[i].flags, ASA_MaxLayerSet))
298 feel->window_boxes[i].max_layer = AS_LayerHighest;
299
300 if (feel->default_window_box_name != NULL) {
301 if (feel->window_boxes[i].name &&
302 mystrcasecmp (feel->window_boxes[i].name,
303 feel->default_window_box_name) == 0)
304 feel->default_window_box = &(feel->window_boxes[i]);
305 }
306 #if !defined(LOCAL_DEBUG) || defined(NO_DEBUG_OUTPUT)
307 if (get_output_threshold () >= OUTPUT_LEVEL_DEBUG)
308 #endif
309 print_window_box (&(feel->window_boxes[i]), i);
310 }
311
312 #if 1
313 if (feel->default_window_box == NULL) { /* build new default windowbox */
314 i = feel->window_boxes_num;
315 feel->window_boxes =
316 realloc (feel->window_boxes, sizeof (ASWindowBox) * (i + 1));
317 ++(feel->window_boxes_num);
318 feel->default_window_box = &(feel->window_boxes[i]);
319 memset (feel->default_window_box, 0x00, sizeof (ASWindowBox));
320 feel->default_window_box->name = mystrdup ("default");
321 feel->default_window_box->area.width = ASDefaultScr->MyDisplayWidth;
322 feel->default_window_box->area.height = ASDefaultScr->MyDisplayHeight;
323 feel->default_window_box->main_strategy = ASP_Manual;
324 feel->default_window_box->backup_strategy = ASP_Manual;
325 /* we should enforce this one : */
326 feel->default_window_box->desk = INVALID_DESK;
327 feel->default_window_box->min_layer = AS_LayerLowest;
328 feel->default_window_box->max_layer = AS_LayerHighest;
329 if (get_flags (feel->deprecated_flags, FEEL_DEPRECATED_SmartPlacement)) {
330 feel->default_window_box->main_strategy = ASP_SmartPlacement;
331 if (get_flags
332 (feel->deprecated_flags, FEEL_DEPRECATED_RandomPlacement))
333 feel->default_window_box->backup_strategy = ASP_RandomPlacement;
334 } else if (get_flags (feel->deprecated_flags, FEEL_DEPRECATED_RandomPlacement)) { /* don't really want to use ManualPlacement if onlyRandomPlacement is requested */
335 feel->default_window_box->main_strategy = ASP_RandomPlacement;
336 feel->default_window_box->backup_strategy = ASP_RandomPlacement;
337 }
338 #if !defined(LOCAL_DEBUG) || defined(NO_DEBUG_OUTPUT)
339 if (get_output_threshold () >= OUTPUT_LEVEL_DEBUG)
340 #endif
341 print_window_box (&(feel->window_boxes[i]), i);
342 }
343 #endif
344 }
345
346 /*************************************************************************
347 * WindowBox utility functions
348 *************************************************************************/
create_aswindow_box(const char * name)349 ASWindowBox *create_aswindow_box (const char *name)
350 {
351 ASWindowBox *aswbox = safecalloc (1, sizeof (ASWindowBox));
352
353 aswbox->name = mystrdup (name);
354 return aswbox;
355 }
356
destroy_aswindow_box(ASWindowBox * aswbox,Bool reusable)357 void destroy_aswindow_box (ASWindowBox * aswbox, Bool reusable)
358 {
359 if (aswbox) {
360 if (aswbox->name)
361 free (aswbox->name);
362 if (!reusable)
363 free (aswbox);
364 else
365 memset (aswbox, 0x00, sizeof (ASWindowBox));
366 }
367 }
368
print_window_box(ASWindowBox * aswbox,int index)369 void print_window_box (ASWindowBox * aswbox, int index)
370 {
371 if (aswbox) {
372 if (aswbox->name)
373 fprintf (stderr, "WindowBox[%d].name = \"%s\";\n", index,
374 aswbox->name);
375 fprintf (stderr, "WindowBox[%d].set_flags = 0x%lX;\n", index,
376 aswbox->set_flags);
377 fprintf (stderr, "WindowBox[%d].flags = 0x%lX;\n", index,
378 aswbox->flags);
379 fprintf (stderr, "WindowBox[%d].area.flags = 0x%X;\n", index,
380 aswbox->area.flags);
381 fprintf (stderr, "WindowBox[%d].area.geometry = %dx%d%+d%+d;\n", index,
382 aswbox->area.width, aswbox->area.height, aswbox->area.x,
383 aswbox->area.y);
384 fprintf (stderr, "WindowBox[%d].min_size = %dx%d;\n", index,
385 aswbox->min_width, aswbox->min_height);
386 fprintf (stderr, "WindowBox[%d].max_size = %dx%d;\n", index,
387 aswbox->max_width, aswbox->max_height);
388 fprintf (stderr, "WindowBox[%d].main_strategy = %d;\n", index,
389 aswbox->main_strategy);
390 fprintf (stderr, "WindowBox[%d].backup_strategy = %d;\n", index,
391 aswbox->backup_strategy);
392 fprintf (stderr, "WindowBox[%d].desk = %d;\n", index, aswbox->desk);
393 fprintf (stderr, "WindowBox[%d].min_layer = %d;\n", index,
394 aswbox->min_layer);
395 fprintf (stderr, "WindowBox[%d].max_layer = %d;\n", index,
396 aswbox->max_layer);
397 }
398 }
399
find_window_box(ASFeel * feel,const char * name)400 ASWindowBox *find_window_box (ASFeel * feel, const char *name)
401 {
402 if (feel && name) {
403 int i = feel->window_boxes_num;
404 ASWindowBox *aswbox = &(feel->window_boxes[0]);
405
406 while (--i >= 0)
407 if (mystrcasecmp (aswbox[i].name, name) == 0)
408 return &(aswbox[i]);
409 }
410 return NULL;
411 }
412
413 /*************************************************************************
414 * Menus :
415 *************************************************************************/
menu_data_destroy(ASHashableValue value,void * data)416 void menu_data_destroy (ASHashableValue value, void *data)
417 {
418 MenuData *md = data;
419
420 #ifdef DEBUG_ALLOCS
421 LOCAL_DEBUG_CALLER_OUT ("menu_data_destroy(\"%s\", %p)", (char *)value,
422 data);
423 #endif
424 if ((char *)value)
425 free ((char *)value);
426 if (md) {
427 if (md->magic == MAGIC_MENU_DATA) {
428 if (md->name == (char *)value)
429 md->name = NULL;
430 destroy_menu_data (&md);
431 }
432 }
433 }
434
init_list_of_menus(ASHashTable ** list,Bool force)435 void init_list_of_menus (ASHashTable ** list, Bool force)
436 {
437 if (list == NULL)
438 return;
439
440 if (force && *list != NULL)
441 destroy_ashash (list);
442
443 if (*list == NULL) {
444 *list =
445 create_ashash (0, casestring_hash_value, casestring_compare,
446 menu_data_destroy);
447 LOCAL_DEBUG_OUT ("created the list of Popups %p", *list);
448 }
449 }
450