Change to the linux kernel coding style
[wmaker-crm.git] / src / screen.c
1 /* screen.c - screen management
2 *
3 * Window Maker window manager
4 *
5 * Copyright (c) 1997-2003 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.
11 *
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.
16 *
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.
21 */
22
23 #include "wconfig.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <X11/Xatom.h>
32 #ifdef SHAPE
33 #include <X11/extensions/shape.h>
34 #endif
35 #ifdef KEEP_XKB_LOCK_STATUS
36 #include <X11/XKBlib.h>
37 #endif /* KEEP_XKB_LOCK_STATUS */
38
39 #include <wraster.h>
40
41 #include "WindowMaker.h"
42 #include "def_pixmaps.h"
43 #include "screen.h"
44 #include "texture.h"
45 #include "pixmap.h"
46 #include "menu.h"
47 #include "funcs.h"
48 #include "actions.h"
49 #include "properties.h"
50 #include "dock.h"
51 #include "resources.h"
52 #include "workspace.h"
53 #include "session.h"
54 #include "balloon.h"
55 #include "geomview.h"
56 #ifdef NETWM_HINTS
57 # include "wmspec.h"
58 #endif
59
60 #include "xinerama.h"
61
62 #include <WINGs/WUtil.h>
63
64 #include "defaults.h"
65
66 #ifdef LITE
67 #define EVENT_MASK (LeaveWindowMask|EnterWindowMask|PropertyChangeMask\
68 |SubstructureNotifyMask|PointerMotionMask \
69 |SubstructureRedirectMask|KeyPressMask|KeyReleaseMask)
70 #else
71 #define EVENT_MASK (LeaveWindowMask|EnterWindowMask|PropertyChangeMask\
72 |SubstructureNotifyMask|PointerMotionMask \
73 |SubstructureRedirectMask|ButtonPressMask|ButtonReleaseMask\
74 |KeyPressMask|KeyReleaseMask)
75 #endif
76
77 /**** Global variables ****/
78
79 extern Cursor wCursor[WCUR_LAST];
80 extern WPreferences wPreferences;
81 extern Atom _XA_WINDOWMAKER_STATE;
82 extern Atom _XA_WINDOWMAKER_NOTICEBOARD;
83
84 extern int wScreenCount;
85
86 #ifdef KEEP_XKB_LOCK_STATUS
87 extern int wXkbSupported;
88 #endif
89
90 extern WDDomain *WDWindowMaker;
91
92 /**** Local ****/
93
94 #define STIPPLE_WIDTH 2
95 #define STIPPLE_HEIGHT 2
96 static char STIPPLE_DATA[] = { 0x02, 0x01 };
97
98 static int CantManageScreen = 0;
99
100 static WMPropList *dApplications = NULL;
101 static WMPropList *dWorkspace;
102 static WMPropList *dDock;
103 static WMPropList *dClip;
104
105 static void make_keys()
106 {
107 if (dApplications != NULL)
108 return;
109
110 dApplications = WMCreatePLString("Applications");
111 dWorkspace = WMCreatePLString("Workspace");
112 dDock = WMCreatePLString("Dock");
113 dClip = WMCreatePLString("Clip");
114 }
115
116 /*
117 *----------------------------------------------------------------------
118 * alreadyRunningError--
119 * X error handler used to catch errors when trying to do
120 * XSelectInput() on the root window. These errors probably mean that
121 * there already is some other window manager running.
122 *
123 * Returns:
124 * Nothing, unless something really evil happens...
125 *
126 * Side effects:
127 * CantManageScreen is set to 1;
128 *----------------------------------------------------------------------
129 */
130 static int alreadyRunningError(Display * dpy, XErrorEvent * error)
131 {
132 CantManageScreen = 1;
133 return -1;
134 }
135
136 /*
137 *----------------------------------------------------------------------
138 * allocButtonPixmaps--
139 * Allocate pixmaps used on window operation buttons (those in the
140 * titlebar). The pixmaps are linked to the program. If XPM is supported
141 * XPM pixmaps are used otherwise, equivalent bitmaps are used.
142 *
143 * Returns:
144 * Nothing
145 *
146 * Side effects:
147 * Allocates shared pixmaps for the screen. These pixmaps should
148 * not be freed by anybody.
149 *----------------------------------------------------------------------
150 */
151 static void allocButtonPixmaps(WScreen * scr)
152 {
153 WPixmap *pix;
154
155 /* create predefined pixmaps */
156 pix = wPixmapCreateFromXPMData(scr, PRED_CLOSE_XPM);
157 if (pix)
158 pix->shared = 1;
159 scr->b_pixmaps[WBUT_CLOSE] = pix;
160
161 pix = wPixmapCreateFromXPMData(scr, PRED_BROKEN_CLOSE_XPM);
162 if (pix)
163 pix->shared = 1;
164 scr->b_pixmaps[WBUT_BROKENCLOSE] = pix;
165
166 pix = wPixmapCreateFromXPMData(scr, PRED_ICONIFY_XPM);
167 if (pix)
168 pix->shared = 1;
169 scr->b_pixmaps[WBUT_ICONIFY] = pix;
170 #ifdef XKB_BUTTON_HINT
171 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP1_XPM);
172 if (pix)
173 pix->shared = 1;
174 scr->b_pixmaps[WBUT_XKBGROUP1] = pix;
175 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP2_XPM);
176 if (pix)
177 pix->shared = 1;
178 scr->b_pixmaps[WBUT_XKBGROUP2] = pix;
179 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP3_XPM);
180 if (pix)
181 pix->shared = 1;
182 scr->b_pixmaps[WBUT_XKBGROUP3] = pix;
183 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP4_XPM);
184 if (pix)
185 pix->shared = 1;
186 scr->b_pixmaps[WBUT_XKBGROUP4] = pix;
187 #endif
188
189 pix = wPixmapCreateFromXPMData(scr, PRED_KILL_XPM);
190 if (pix)
191 pix->shared = 1;
192 scr->b_pixmaps[WBUT_KILL] = pix;
193 }
194
195 static void draw_dot(WScreen * scr, Drawable d, int x, int y, GC gc)
196 {
197 XSetForeground(dpy, gc, scr->black_pixel);
198 XDrawLine(dpy, d, gc, x, y, x + 1, y);
199 XDrawPoint(dpy, d, gc, x, y + 1);
200 XSetForeground(dpy, gc, scr->white_pixel);
201 XDrawLine(dpy, d, gc, x + 2, y, x + 2, y + 1);
202 XDrawPoint(dpy, d, gc, x + 1, y + 1);
203 }
204
205 static WPixmap *make3Dots(WScreen * scr)
206 {
207 WPixmap *wpix;
208 GC gc2, gc;
209 XGCValues gcv;
210 Pixmap pix, mask;
211
212 gc = scr->copy_gc;
213 pix = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, wPreferences.icon_size, scr->w_depth);
214 XSetForeground(dpy, gc, scr->black_pixel);
215 XFillRectangle(dpy, pix, gc, 0, 0, wPreferences.icon_size, wPreferences.icon_size);
216 XSetForeground(dpy, gc, scr->white_pixel);
217 draw_dot(scr, pix, 4, wPreferences.icon_size - 6, gc);
218 draw_dot(scr, pix, 9, wPreferences.icon_size - 6, gc);
219 draw_dot(scr, pix, 14, wPreferences.icon_size - 6, gc);
220
221 mask = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, wPreferences.icon_size, 1);
222 gcv.foreground = 0;
223 gcv.graphics_exposures = False;
224 gc2 = XCreateGC(dpy, mask, GCForeground | GCGraphicsExposures, &gcv);
225 XFillRectangle(dpy, mask, gc2, 0, 0, wPreferences.icon_size, wPreferences.icon_size);
226 XSetForeground(dpy, gc2, 1);
227 XFillRectangle(dpy, mask, gc2, 4, wPreferences.icon_size - 6, 3, 2);
228 XFillRectangle(dpy, mask, gc2, 9, wPreferences.icon_size - 6, 3, 2);
229 XFillRectangle(dpy, mask, gc2, 14, wPreferences.icon_size - 6, 3, 2);
230
231 XFreeGC(dpy, gc2);
232
233 wpix = wPixmapCreate(scr, pix, mask);
234 wpix->shared = 1;
235
236 return wpix;
237 }
238
239 static void allocGCs(WScreen * scr)
240 {
241 XGCValues gcv;
242 XColor color;
243 int gcm;
244
245 scr->stipple_bitmap = XCreateBitmapFromData(dpy, scr->w_win, STIPPLE_DATA, STIPPLE_WIDTH, STIPPLE_HEIGHT);
246
247 gcv.stipple = scr->stipple_bitmap;
248 gcv.foreground = scr->white_pixel;
249 gcv.fill_style = FillStippled;
250 gcv.graphics_exposures = False;
251 gcm = GCForeground | GCStipple | GCFillStyle | GCGraphicsExposures;
252 scr->stipple_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
253
254 /* selected icon border GCs */
255 gcv.function = GXcopy;
256 gcv.foreground = scr->white_pixel;
257 gcv.background = scr->black_pixel;
258 gcv.line_width = 1;
259 gcv.line_style = LineDoubleDash;
260 gcv.fill_style = FillSolid;
261 gcv.dash_offset = 0;
262 gcv.dashes = 4;
263 gcv.graphics_exposures = False;
264
265 gcm = GCFunction | GCGraphicsExposures;
266 gcm |= GCForeground | GCBackground;
267 gcm |= GCLineWidth | GCLineStyle;
268 gcm |= GCFillStyle;
269 gcm |= GCDashOffset | GCDashList;
270
271 scr->icon_select_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
272
273 scr->menu_title_color[0] = WMRetainColor(scr->white);
274
275 /* don't retain scr->black here because we may alter its alpha */
276 scr->mtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
277 scr->dtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
278
279 /* frame GC */
280 wGetColor(scr, DEF_FRAME_COLOR, &color);
281 gcv.function = GXxor;
282 /* this will raise the probability of the XORed color being different
283 * of the original color in PseudoColor when not all color cells are
284 * initialized */
285 if (DefaultVisual(dpy, scr->screen)->class == PseudoColor)
286 gcv.plane_mask = (1 << (scr->depth - 1)) | 1;
287 else
288 gcv.plane_mask = AllPlanes;
289 gcv.foreground = color.pixel;
290 if (gcv.foreground == 0)
291 gcv.foreground = 1;
292 gcv.line_width = DEF_FRAME_THICKNESS;
293 gcv.subwindow_mode = IncludeInferiors;
294 gcv.graphics_exposures = False;
295 scr->frame_gc = XCreateGC(dpy, scr->root_win, GCForeground | GCGraphicsExposures
296 | GCFunction | GCSubwindowMode | GCLineWidth | GCPlaneMask, &gcv);
297
298 /* line GC */
299 gcv.foreground = color.pixel;
300
301 if (gcv.foreground == 0)
302 /* XOR:ing with a zero is not going to be of much use, so
303 in that case, we somewhat arbitrarily xor with 17 instead. */
304 gcv.foreground = 17;
305
306 gcv.function = GXxor;
307 gcv.subwindow_mode = IncludeInferiors;
308 gcv.line_width = 1;
309 gcv.cap_style = CapRound;
310 gcv.graphics_exposures = False;
311 gcm = GCForeground | GCFunction | GCSubwindowMode | GCLineWidth | GCCapStyle | GCGraphicsExposures;
312 scr->line_gc = XCreateGC(dpy, scr->root_win, gcm, &gcv);
313
314 scr->line_pixel = gcv.foreground;
315
316 /* copy GC */
317 gcv.foreground = scr->white_pixel;
318 gcv.background = scr->black_pixel;
319 gcv.graphics_exposures = False;
320 scr->copy_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
321
322 /* misc drawing GC */
323 gcv.graphics_exposures = False;
324 gcm = GCGraphicsExposures;
325 scr->draw_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
326
327 assert(scr->stipple_bitmap != None);
328
329 /* mono GC */
330 scr->mono_gc = XCreateGC(dpy, scr->stipple_bitmap, gcm, &gcv);
331 }
332
333 static void createPixmaps(WScreen * scr)
334 {
335 WPixmap *pix;
336 RImage *image;
337
338 /* load pixmaps */
339 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_RADIO_INDICATOR_XBM_DATA,
340 (char *)MENU_RADIO_INDICATOR_XBM_DATA,
341 MENU_RADIO_INDICATOR_XBM_SIZE,
342 MENU_RADIO_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
343 if (pix != NULL)
344 pix->shared = 1;
345 scr->menu_radio_indicator = pix;
346
347 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_CHECK_INDICATOR_XBM_DATA,
348 (char *)MENU_CHECK_INDICATOR_XBM_DATA,
349 MENU_CHECK_INDICATOR_XBM_SIZE,
350 MENU_CHECK_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
351 if (pix != NULL)
352 pix->shared = 1;
353 scr->menu_check_indicator = pix;
354
355 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_MINI_INDICATOR_XBM_DATA,
356 (char *)MENU_MINI_INDICATOR_XBM_DATA,
357 MENU_MINI_INDICATOR_XBM_SIZE,
358 MENU_MINI_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
359 if (pix != NULL)
360 pix->shared = 1;
361 scr->menu_mini_indicator = pix;
362
363 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_HIDE_INDICATOR_XBM_DATA,
364 (char *)MENU_HIDE_INDICATOR_XBM_DATA,
365 MENU_HIDE_INDICATOR_XBM_SIZE,
366 MENU_HIDE_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
367 if (pix != NULL)
368 pix->shared = 1;
369 scr->menu_hide_indicator = pix;
370
371 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_SHADE_INDICATOR_XBM_DATA,
372 (char *)MENU_SHADE_INDICATOR_XBM_DATA,
373 MENU_SHADE_INDICATOR_XBM_SIZE,
374 MENU_SHADE_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
375 if (pix != NULL)
376 pix->shared = 1;
377 scr->menu_shade_indicator = pix;
378
379 image = wDefaultGetImage(scr, "Logo", "WMPanel");
380
381 if (!image) {
382 wwarning(_("could not load logo image for panels: %s"), RMessageForError(RErrorCode));
383 } else {
384 WMSetApplicationIconImage(scr->wmscreen, image);
385 RReleaseImage(image);
386 }
387
388 scr->dock_dots = make3Dots(scr);
389
390 /* titlebar button pixmaps */
391 allocButtonPixmaps(scr);
392 }
393
394 /*
395 *----------------------------------------------------------------------
396 * createInternalWindows--
397 * Creates some windows used internally by the program. One to
398 * receive input focus when no other window can get it and another
399 * to display window geometry information during window resize/move.
400 *
401 * Returns:
402 * Nothing
403 *
404 * Side effects:
405 * Windows are created and some colors are allocated for the
406 * window background.
407 *----------------------------------------------------------------------
408 */
409 static void createInternalWindows(WScreen * scr)
410 {
411 int vmask;
412 XSetWindowAttributes attribs;
413
414 /* InputOnly window to get the focus when no other window can get it */
415 vmask = CWEventMask | CWOverrideRedirect;
416 attribs.event_mask = KeyPressMask | FocusChangeMask;
417 attribs.override_redirect = True;
418 scr->no_focus_win = XCreateWindow(dpy, scr->root_win, -10, -10, 4, 4, 0, 0,
419 InputOnly, CopyFromParent, vmask, &attribs);
420 XSelectInput(dpy, scr->no_focus_win, KeyPressMask | KeyReleaseMask);
421 XMapWindow(dpy, scr->no_focus_win);
422
423 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
424
425 /* shadow window for dock buttons */
426 vmask = CWBorderPixel | CWBackPixmap | CWBackPixel | CWCursor | CWSaveUnder | CWOverrideRedirect;
427 attribs.border_pixel = scr->black_pixel;
428 attribs.save_under = True;
429 attribs.override_redirect = True;
430 attribs.background_pixmap = None;
431 attribs.background_pixel = scr->white_pixel;
432 attribs.cursor = wCursor[WCUR_DEFAULT];
433 vmask |= CWColormap;
434 attribs.colormap = scr->w_colormap;
435 scr->dock_shadow =
436 XCreateWindow(dpy, scr->root_win, 0, 0, wPreferences.icon_size,
437 wPreferences.icon_size, 0, scr->w_depth, CopyFromParent, scr->w_visual, vmask, &attribs);
438
439 /* workspace name balloon for clip */
440 vmask = CWBackPixel | CWSaveUnder | CWOverrideRedirect | CWColormap | CWBorderPixel;
441 attribs.save_under = True;
442 attribs.override_redirect = True;
443 attribs.colormap = scr->w_colormap;
444 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
445 attribs.border_pixel = 0; /* do not care */
446 scr->clip_balloon =
447 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
448 CopyFromParent, scr->w_visual, vmask, &attribs);
449
450 /* workspace name */
451 vmask = CWBackPixel | CWSaveUnder | CWOverrideRedirect | CWColormap | CWBorderPixel;
452 attribs.save_under = True;
453 attribs.override_redirect = True;
454 attribs.colormap = scr->w_colormap;
455 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
456 attribs.border_pixel = 0; /* do not care */
457 scr->workspace_name =
458 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
459 CopyFromParent, scr->w_visual, vmask, &attribs);
460
461 /*
462 * If the window is clicked without having ButtonPress selected, the
463 * resulting event will have event.xbutton.window == root.
464 */
465 XSelectInput(dpy, scr->clip_balloon, ButtonPressMask);
466 }
467
468 #if 0
469 static Bool aquireManagerSelection(WScreen * scr)
470 {
471 char buffer[32];
472 XEvent ev;
473 Time timestamp;
474
475 snprintf(buffer, sizeof(buffer), "WM_S%i", scr->screen);
476 scr->managerAtom = XInternAtom(dpy, buffer, False);
477
478 /* for race-conditions... */
479 XGrabServer(dpy);
480
481 /* if there is another manager running, don't try to replace it
482 * (for now, at least) */
483 if (XGetSelectionOwner(dpy, scr->managerAtom) != None) {
484 XUngrabServer(dpy);
485 return False;
486 }
487
488 /* become the manager for this screen */
489
490 scr->managerWindow = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 1, 1, 0, 0, 0);
491
492 XSelectInput(dpy, scr->managerWindow, PropertyChangeMask);
493 /* get a timestamp */
494 XChangeProperty(dpy, scr->managerWindow, scr->managerAtom, XA_INTEGER, 32, PropModeAppend, NULL, 0);
495 while (1) {
496 XWindowEvent(dpy, scr->managerWindow, &ev);
497 if (ev.type == PropertyNotify) {
498 timestamp = ev.xproperty.time;
499 break;
500 }
501 }
502 XSelectInput(dpy, scr->managerWindow, NoEvents);
503 XDeleteProperty(dpy, scr->managerWindow, scr->managerAtom);
504
505 XSetSelectionOwner(dpy, scr->managerAtom, scr->managerWindow, CurrentTime);
506
507 XUngrabServer(dpy);
508
509 /* announce our arrival */
510
511 ev.xclient.type = ClientMessage;
512 ev.xclient.message_type = XInternAtom(dpy, "MANAGER", False);
513 ev.xclient.destination = scr->root_win;
514 ev.xclient.format = 32;
515 ev.xclient.data.l[0] = timestamp;
516 ev.xclient.data.l[1] = scr->managerAtom;
517 ev.xclient.data.l[2] = scr->managerWindow;
518 ev.xclient.data.l[3] = 0;
519 ev.xclient.data.l[4] = 0;
520
521 XSendEvent(dpy, scr->root_win, False, StructureNotify, &ev);
522 XSync(dpy, False);
523
524 return True;
525 }
526 #endif
527
528 /*
529 *----------------------------------------------------------------------
530 * wScreenInit--
531 * Initializes the window manager for the given screen and
532 * allocates a WScreen descriptor for it. Many resources are allocated
533 * for the screen and the root window is setup appropriately.
534 *
535 * Returns:
536 * The WScreen descriptor for the screen.
537 *
538 * Side effects:
539 * Many resources are allocated and the IconSize property is
540 * set on the root window.
541 * The program can be aborted if some fatal error occurs.
542 *
543 * TODO: User specifiable visual.
544 *----------------------------------------------------------------------
545 */
546 WScreen *wScreenInit(int screen_number)
547 {
548 WScreen *scr;
549 XIconSize icon_size[1];
550 RContextAttributes rattr;
551 extern int wVisualID;
552 long event_mask;
553 XErrorHandler oldHandler;
554 int i;
555
556 scr = wmalloc(sizeof(WScreen));
557 memset(scr, 0, sizeof(WScreen));
558
559 scr->stacking_list = WMCreateTreeBag();
560
561 /* initialize globals */
562 scr->screen = screen_number;
563 scr->root_win = RootWindow(dpy, screen_number);
564 scr->depth = DefaultDepth(dpy, screen_number);
565 scr->colormap = DefaultColormap(dpy, screen_number);
566
567 scr->scr_width = WidthOfScreen(ScreenOfDisplay(dpy, screen_number));
568 scr->scr_height = HeightOfScreen(ScreenOfDisplay(dpy, screen_number));
569
570 wInitXinerama(scr);
571
572 scr->usableArea = (WArea *) wmalloc(sizeof(WArea) * wXineramaHeads(scr));
573 scr->totalUsableArea = (WArea *) wmalloc(sizeof(WArea) * wXineramaHeads(scr));
574
575 for (i = 0; i < wXineramaHeads(scr); ++i) {
576 WMRect rect = wGetRectForHead(scr, i);
577 scr->usableArea[i].x1 = scr->totalUsableArea[i].x1 = rect.pos.x;
578 scr->usableArea[i].y1 = scr->totalUsableArea[i].y1 = rect.pos.y;
579 scr->usableArea[i].x2 = scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
580 scr->usableArea[i].y2 = scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
581 }
582
583 scr->fakeGroupLeaders = WMCreateArray(16);
584
585 #if 0
586 if (!aquireManagerSelection(scr)) {
587 wfree(scr);
588
589 return NULL;
590 }
591 #endif
592 CantManageScreen = 0;
593 oldHandler = XSetErrorHandler((XErrorHandler) alreadyRunningError);
594
595 event_mask = EVENT_MASK;
596
597 if (wPreferences.disable_root_mouse) {
598 event_mask &= ~(ButtonPressMask | ButtonReleaseMask);
599 }
600
601 XSelectInput(dpy, scr->root_win, event_mask);
602
603 #ifdef KEEP_XKB_LOCK_STATUS
604 /* Only GroupLock doesn't work correctly in my system since right-alt
605 * can change mode while holding it too - ]d
606 */
607 if (wXkbSupported) {
608 XkbSelectEvents(dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask);
609 }
610 #endif /* KEEP_XKB_LOCK_STATUS */
611
612 XSync(dpy, False);
613 XSetErrorHandler(oldHandler);
614
615 if (CantManageScreen) {
616 wfree(scr);
617 return NULL;
618 }
619
620 XDefineCursor(dpy, scr->root_win, wCursor[WCUR_ROOT]);
621
622 /* screen descriptor for raster graphic library */
623 rattr.flags = RC_RenderMode | RC_ColorsPerChannel | RC_StandardColormap;
624 rattr.render_mode = wPreferences.no_dithering ? RBestMatchRendering : RDitheredRendering;
625
626 /* if the std colormap stuff works ok, this will be ignored */
627 rattr.colors_per_channel = wPreferences.cmap_size;
628 if (rattr.colors_per_channel < 2)
629 rattr.colors_per_channel = 2;
630
631 /* will only be accounted for in PseudoColor */
632 if (wPreferences.flags.create_stdcmap) {
633 rattr.standard_colormap_mode = RCreateStdColormap;
634 } else {
635 rattr.standard_colormap_mode = RUseStdColormap;
636 }
637
638 if (wVisualID >= 0) {
639 rattr.flags |= RC_VisualID;
640 rattr.visualid = wVisualID;
641 }
642
643 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
644
645 if (!scr->rcontext && RErrorCode == RERR_STDCMAPFAIL) {
646 wwarning(RMessageForError(RErrorCode));
647
648 rattr.flags &= ~RC_StandardColormap;
649 rattr.standard_colormap_mode = RUseStdColormap;
650
651 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
652 }
653
654 if (!scr->rcontext) {
655 wwarning(_("could not initialize graphics library context: %s"), RMessageForError(RErrorCode));
656 wAbort(False);
657 } else {
658 char **formats;
659 int i = 0;
660
661 formats = RSupportedFileFormats();
662 if (formats) {
663 for (i = 0; formats[i] != NULL; i++) {
664 if (strcmp(formats[i], "TIFF") == 0) {
665 scr->flags.supports_tiff = 1;
666 break;
667 }
668 }
669 }
670 }
671
672 scr->w_win = scr->rcontext->drawable;
673 scr->w_visual = scr->rcontext->visual;
674 scr->w_depth = scr->rcontext->depth;
675 scr->w_colormap = scr->rcontext->cmap;
676
677 /* create screen descriptor for WINGs */
678 scr->wmscreen = WMCreateScreenWithRContext(dpy, screen_number, scr->rcontext);
679
680 if (!scr->wmscreen) {
681 wfatal(_("could not initialize WINGs widget set"));
682 return NULL;
683 }
684
685 scr->black = WMBlackColor(scr->wmscreen);
686 scr->white = WMWhiteColor(scr->wmscreen);
687 scr->gray = WMGrayColor(scr->wmscreen);
688 scr->darkGray = WMDarkGrayColor(scr->wmscreen);
689
690 scr->black_pixel = WMColorPixel(scr->black); /*scr->rcontext->black; */
691 scr->white_pixel = WMColorPixel(scr->white); /*scr->rcontext->white; */
692 scr->light_pixel = WMColorPixel(scr->gray);
693 scr->dark_pixel = WMColorPixel(scr->darkGray);
694
695 {
696 XColor xcol;
697 /* frame boder color */
698 wGetColor(scr, FRAME_BORDER_COLOR, &xcol);
699 scr->frame_border_pixel = xcol.pixel;
700 }
701
702 /* create GCs with default values */
703 allocGCs(scr);
704
705 /* for our window manager info notice board. Need to
706 * create before reading the defaults, because it will be used there.
707 */
708 scr->info_window = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, 0, 0);
709
710 /* read defaults for this screen */
711 wReadDefaults(scr, WDWindowMaker->dictionary);
712
713 createInternalWindows(scr);
714
715 #ifdef NETWM_HINTS
716 wNETWMInitStuff(scr);
717 #endif
718
719 /* create initial workspace */
720 wWorkspaceNew(scr);
721
722 /* create shared pixmaps */
723 createPixmaps(scr);
724
725 /* set icon sizes we can accept from clients */
726 icon_size[0].min_width = 8;
727 icon_size[0].min_height = 8;
728 icon_size[0].max_width = wPreferences.icon_size - 4;
729 icon_size[0].max_height = wPreferences.icon_size - 4;
730 icon_size[0].width_inc = 1;
731 icon_size[0].height_inc = 1;
732 XSetIconSizes(dpy, scr->root_win, icon_size, 1);
733
734 /* setup WindowMaker protocols property in the root window */
735 PropSetWMakerProtocols(scr->root_win);
736
737 /* setup our noticeboard */
738 XChangeProperty(dpy, scr->info_window, _XA_WINDOWMAKER_NOTICEBOARD,
739 XA_WINDOW, 32, PropModeReplace, (unsigned char *)&scr->info_window, 1);
740 XChangeProperty(dpy, scr->root_win, _XA_WINDOWMAKER_NOTICEBOARD,
741 XA_WINDOW, 32, PropModeReplace, (unsigned char *)&scr->info_window, 1);
742
743 #ifdef BALLOON_TEXT
744 /* initialize balloon text stuff */
745 wBalloonInitialize(scr);
746 #endif
747
748 scr->info_text_font = WMBoldSystemFontOfSize(scr->wmscreen, 12);
749
750 scr->tech_draw_font = XLoadQueryFont(dpy, "-adobe-helvetica-bold-r-*-*-12-*-*-*-*-*-*-*");
751 if (!scr->tech_draw_font)
752 scr->tech_draw_font = XLoadQueryFont(dpy, "fixed");
753
754 scr->gview = WCreateGeometryView(scr->wmscreen);
755 WMRealizeWidget(scr->gview);
756
757 wScreenUpdateUsableArea(scr);
758
759 return scr;
760 }
761
762 void wScreenUpdateUsableArea(WScreen * scr)
763 {
764 /*
765 * scr->totalUsableArea[] will become the usableArea used for Windowplacement,
766 * scr->usableArea[] will be used for iconplacement, hence no iconyard nor
767 * border.
768 */
769
770 int i;
771 unsigned long best_area = 0, tmp_area;
772 WArea area;
773 int dock_head = scr->xine_info.primary_head;
774
775 if (scr->dock) {
776 WMRect rect;
777 rect.pos.x = scr->dock->x_pos;
778 rect.pos.y = scr->dock->y_pos;
779 rect.size.width = wPreferences.icon_size;
780 rect.size.height = wPreferences.icon_size;
781 dock_head = wGetHeadForRect(scr, rect);
782 }
783
784 for (i = 0; i < wXineramaHeads(scr); ++i) {
785 WMRect rect = wGetRectForHead(scr, i);
786 scr->totalUsableArea[i].x1 = rect.pos.x;
787 scr->totalUsableArea[i].y1 = rect.pos.y;
788 scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
789 scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
790
791 if (scr->dock && dock_head == i && (!scr->dock->lowered || wPreferences.no_window_over_dock)) {
792 int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
793
794 if (scr->dock->on_right_side) {
795 scr->totalUsableArea[i].x2 -= offset;
796 } else {
797 scr->totalUsableArea[i].x1 += offset;
798 }
799 }
800 #ifdef NETWM_HINTS
801 {
802 WArea area;
803 if (wNETWMGetUsableArea(scr, i, &area)) {
804 scr->totalUsableArea[i].x1 = WMAX(scr->totalUsableArea[i].x1, area.x1);
805 scr->totalUsableArea[i].y1 = WMAX(scr->totalUsableArea[i].y1, area.y1);
806 scr->totalUsableArea[i].x2 = WMIN(scr->totalUsableArea[i].x2, area.x2);
807 scr->totalUsableArea[i].y2 = WMIN(scr->totalUsableArea[i].y2, area.y2);
808 }
809 }
810 #endif
811
812 scr->usableArea[i] = scr->totalUsableArea[i];
813
814 #if 0
815 printf("usableArea[%d]: %d %d %d %d\n", i,
816 scr->usableArea[i].x1, scr->usableArea[i].x2, scr->usableArea[i].y1, scr->usableArea[i].y2);
817 #endif
818
819 if (wPreferences.no_window_over_icons) {
820 if (wPreferences.icon_yard & IY_VERT) {
821 if (wPreferences.icon_yard & IY_RIGHT) {
822 scr->totalUsableArea[i].x2 -= wPreferences.icon_size;
823 } else {
824 scr->totalUsableArea[i].x1 += wPreferences.icon_size;
825 }
826 } else {
827 if (wPreferences.icon_yard & IY_TOP) {
828 scr->totalUsableArea[i].y1 += wPreferences.icon_size;
829 } else {
830 scr->totalUsableArea[i].y2 -= wPreferences.icon_size;
831 }
832 }
833 }
834
835 if (scr->totalUsableArea[i].x2 - scr->totalUsableArea[i].x1 < rect.size.width / 2) {
836 scr->totalUsableArea[i].x1 = rect.pos.x;
837 scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
838 }
839
840 if (scr->totalUsableArea[i].y2 - scr->totalUsableArea[i].y1 < rect.size.height / 2) {
841 scr->totalUsableArea[i].y1 = rect.pos.y;
842 scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
843 }
844
845 tmp_area = (scr->totalUsableArea[i].x2 - scr->totalUsableArea[i].x1) *
846 (scr->totalUsableArea[i].y2 - scr->totalUsableArea[i].y1);
847
848 if (tmp_area > best_area) {
849 best_area = tmp_area;
850 area = scr->totalUsableArea[i];
851 }
852
853 {
854 unsigned size = wPreferences.workspace_border_size;
855 unsigned position = wPreferences.workspace_border_position;
856
857 if (size > 0 && position != WB_NONE) {
858 if (position & WB_LEFTRIGHT) {
859 scr->totalUsableArea[i].x1 += size;
860 scr->totalUsableArea[i].x2 -= size;
861 }
862 if (position & WB_TOPBOTTOM) {
863 scr->totalUsableArea[i].y1 += size;
864 scr->totalUsableArea[i].y2 -= size;
865 }
866 }
867 }
868 }
869
870 #ifdef NETWM_HINTS
871 wNETWMUpdateWorkarea(scr, area);
872 #endif
873
874 if (wPreferences.auto_arrange_icons) {
875 wArrangeIcons(scr, True);
876 }
877 }
878
879 #if 0
880 void wScreenUpdateUsableArea(WScreen * scr)
881 {
882 scr->totalUsableArea = scr->usableArea;
883
884 if (scr->dock && (!scr->dock->lowered || wPreferences.no_window_over_dock)) {
885
886 int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
887
888 if (scr->dock->on_right_side) {
889 scr->totalUsableArea.x2 = WMIN(scr->totalUsableArea.x2, scr->scr_width - offset);
890 } else {
891 scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, offset);
892 }
893 }
894
895 if (wPreferences.no_window_over_icons) {
896 if (wPreferences.icon_yard & IY_VERT) {
897
898 if (!(wPreferences.icon_yard & IY_RIGHT)) {
899 scr->totalUsableArea.x1 += wPreferences.icon_size;
900 } else {
901 scr->totalUsableArea.x2 -= wPreferences.icon_size;
902 }
903 } else {
904
905 if (wPreferences.icon_yard & IY_TOP) {
906 scr->totalUsableArea.y1 += wPreferences.icon_size;
907 } else {
908 scr->totalUsableArea.y2 -= wPreferences.icon_size;
909 }
910 }
911 }
912 #ifdef NETWM_HINTS
913 {
914 WArea area;
915 if (wNETWMGetUsableArea(scr, &area)) {
916 scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, area.x1);
917 scr->totalUsableArea.y1 = WMAX(scr->totalUsableArea.y1, area.y1);
918 scr->totalUsableArea.x2 = WMIN(scr->totalUsableArea.x2, area.x2);
919 scr->totalUsableArea.y2 = WMIN(scr->totalUsableArea.y2, area.y2);
920 }
921 }
922 #endif
923
924 if (scr->totalUsableArea.x2 - scr->totalUsableArea.x1 < scr->scr_width / 2) {
925 scr->totalUsableArea.x2 = scr->usableArea.x2;
926 scr->totalUsableArea.x1 = scr->usableArea.x1;
927 }
928 if (scr->totalUsableArea.y2 - scr->totalUsableArea.y1 < scr->scr_height / 2) {
929 scr->totalUsableArea.y2 = scr->usableArea.y2;
930 scr->totalUsableArea.y1 = scr->usableArea.y1;
931 }
932 #ifdef NETWM_HINTS
933 wNETWMUpdateWorkarea(scr);
934 #endif
935
936 {
937 unsigned size = wPreferences.workspace_border_size;
938 unsigned position = wPreferences.workspace_border_position;
939
940 if (size > 0 && position != WB_NONE) {
941 if (position & WB_LEFTRIGHT) {
942 scr->totalUsableArea.x1 += size;
943 scr->totalUsableArea.x2 -= size;
944 }
945 if (position & WB_TOPBOTTOM) {
946 scr->totalUsableArea.y1 += size;
947 scr->totalUsableArea.y2 -= size;
948 }
949 }
950 }
951
952 if (wPreferences.auto_arrange_icons) {
953 wArrangeIcons(scr, True);
954 }
955 }
956 #endif
957
958 void wScreenRestoreState(WScreen * scr)
959 {
960 WMPropList *state;
961 char *path;
962
963 #ifndef LITE
964 OpenRootMenu(scr, -10000, -10000, False);
965 wMenuUnmap(scr->root_menu);
966 #endif
967
968 make_keys();
969
970 if (wScreenCount == 1) {
971 path = wdefaultspathfordomain("WMState");
972 } else {
973 char buf[16];
974 snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
975 path = wdefaultspathfordomain(buf);
976 }
977 scr->session_state = WMReadPropListFromFile(path);
978 wfree(path);
979 if (!scr->session_state && wScreenCount > 1) {
980 path = wdefaultspathfordomain("WMState");
981 scr->session_state = WMReadPropListFromFile(path);
982 wfree(path);
983 }
984
985 if (!scr->session_state) {
986 scr->session_state = WMCreatePLDictionary(NULL, NULL);
987 }
988
989 if (!wPreferences.flags.nodock) {
990 state = WMGetFromPLDictionary(scr->session_state, dDock);
991 scr->dock = wDockRestoreState(scr, state, WM_DOCK);
992 }
993
994 if (!wPreferences.flags.noclip) {
995 state = WMGetFromPLDictionary(scr->session_state, dClip);
996 scr->clip_icon = wClipRestoreState(scr, state);
997 }
998
999 wWorkspaceRestoreState(scr);
1000
1001 wScreenUpdateUsableArea(scr);
1002 }
1003
1004 void wScreenSaveState(WScreen * scr)
1005 {
1006 WWindow *wwin;
1007 char *str;
1008 WMPropList *old_state, *foo;
1009
1010 make_keys();
1011
1012 /* save state of windows */
1013 wwin = scr->focused_window;
1014 while (wwin) {
1015 wWindowSaveState(wwin);
1016 wwin = wwin->prev;
1017 }
1018
1019 if (wPreferences.flags.noupdates)
1020 return;
1021
1022 old_state = scr->session_state;
1023 scr->session_state = WMCreatePLDictionary(NULL, NULL);
1024
1025 WMPLSetCaseSensitive(True);
1026
1027 /* save dock state to file */
1028 if (!wPreferences.flags.nodock) {
1029 wDockSaveState(scr, old_state);
1030 } else {
1031 if ((foo = WMGetFromPLDictionary(old_state, dDock)) != NULL) {
1032 WMPutInPLDictionary(scr->session_state, dDock, foo);
1033 }
1034 }
1035 if (!wPreferences.flags.noclip) {
1036 wClipSaveState(scr);
1037 } else {
1038 if ((foo = WMGetFromPLDictionary(old_state, dClip)) != NULL) {
1039 WMPutInPLDictionary(scr->session_state, dClip, foo);
1040 }
1041 }
1042
1043 wWorkspaceSaveState(scr, old_state);
1044
1045 if (wPreferences.save_session_on_exit) {
1046 wSessionSaveState(scr);
1047 } else {
1048 if ((foo = WMGetFromPLDictionary(old_state, dApplications)) != NULL) {
1049 WMPutInPLDictionary(scr->session_state, dApplications, foo);
1050 }
1051 if ((foo = WMGetFromPLDictionary(old_state, dWorkspace)) != NULL) {
1052 WMPutInPLDictionary(scr->session_state, dWorkspace, foo);
1053 }
1054 }
1055
1056 /* clean up */
1057 WMPLSetCaseSensitive(False);
1058
1059 wMenuSaveState(scr);
1060
1061 if (wScreenCount == 1) {
1062 str = wdefaultspathfordomain("WMState");
1063 } else {
1064 char buf[16];
1065 snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
1066 str = wdefaultspathfordomain(buf);
1067 }
1068 if (!WMWritePropListToFile(scr->session_state, str, True)) {
1069 wsyserror(_("could not save session state in %s"), str);
1070 }
1071 wfree(str);
1072 WMReleasePropList(old_state);
1073 }
1074
1075 int wScreenBringInside(WScreen * scr, int *x, int *y, int width, int height)
1076 {
1077 int moved = 0;
1078 int tol_w, tol_h;
1079 /*
1080 * With respect to the head that contains most of the window.
1081 */
1082 int sx1, sy1, sx2, sy2;
1083
1084 WMRect rect;
1085 int head, flags;
1086
1087 rect.pos.x = *x;
1088 rect.pos.y = *y;
1089 rect.size.width = width;
1090 rect.size.height = height;
1091
1092 head = wGetRectPlacementInfo(scr, rect, &flags);
1093 rect = wGetRectForHead(scr, head);
1094
1095 sx1 = rect.pos.x;
1096 sy1 = rect.pos.y;
1097 sx2 = sx1 + rect.size.width;
1098 sy2 = sy1 + rect.size.height;
1099
1100 #if 0 /* NOTE: gives funky group movement */
1101 if (flags & XFLAG_MULTIPLE) {
1102 /*
1103 * since we span multiple heads, pull window totaly inside
1104 */
1105 if (*x < sx1)
1106 *x = sx1, moved = 1;
1107 else if (*x + width > sx2)
1108 *x = sx2 - width, moved = 1;
1109
1110 if (*y < sy1)
1111 *y = sy1, moved = 1;
1112 else if (*y + height > sy2)
1113 *y = sy2 - height, moved = 1;
1114
1115 return moved;
1116 }
1117 #endif
1118
1119 if (width > 20)
1120 tol_w = width / 2;
1121 else
1122 tol_w = 20;
1123
1124 if (height > 20)
1125 tol_h = height / 2;
1126 else
1127 tol_h = 20;
1128
1129 if (*x + width < sx1 + 10)
1130 *x = sx1 - tol_w, moved = 1;
1131 else if (*x >= sx2 - 10)
1132 *x = sx2 - tol_w - 1, moved = 1;
1133
1134 if (*y < sy1 - height + 10)
1135 *y = sy1 - tol_h, moved = 1;
1136 else if (*y >= sy2 - 10)
1137 *y = sy2 - tol_h - 1, moved = 1;
1138
1139 return moved;
1140 }
1141
1142 int wScreenKeepInside(WScreen * scr, int *x, int *y, int width, int height)
1143 {
1144 int moved = 0;
1145 int sx1, sy1, sx2, sy2;
1146 WMRect rect;
1147 int head;
1148
1149 rect.pos.x = *x;
1150 rect.pos.y = *y;
1151 rect.size.width = width;
1152 rect.size.height = height;
1153
1154 head = wGetHeadForRect(scr, rect);
1155 rect = wGetRectForHead(scr, head);
1156
1157 sx1 = rect.pos.x;
1158 sy1 = rect.pos.y;
1159 sx2 = sx1 + rect.size.width;
1160 sy2 = sy1 + rect.size.height;
1161
1162 if (*x < sx1)
1163 *x = sx1, moved = 1;
1164 else if (*x + width > sx2)
1165 *x = sx2 - width, moved = 1;
1166
1167 if (*y < sy1)
1168 *y = sy1, moved = 1;
1169 else if (*y + height > sy2)
1170 *y = sy2 - height, moved = 1;
1171
1172 return moved;
1173 }