Fixes relate to modelock.
[wmaker-crm.git] / src / screen.c
blobee287a147e753d30c97c54d6951d7fb8198b31f2
1 /* screen.c - screen management
2 *
3 * Window Maker window manager
4 *
5 * Copyright (c) 1997, 1998 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.
23 #include "wconfig.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
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 */
39 #include <wraster.h>
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 #ifdef KWM_HINTS
56 # include "kwm.h"
57 #endif
58 #ifdef GNOME_STUFF
59 # include "gnome.h"
60 #endif
61 #ifdef OLWM_HINTS
62 # include "openlook.h"
63 #endif
65 #include <proplist.h>
67 #include "defaults.h"
70 #ifdef LITE
71 #define EVENT_MASK (LeaveWindowMask|EnterWindowMask|PropertyChangeMask\
72 |SubstructureNotifyMask|PointerMotionMask \
73 |SubstructureRedirectMask|KeyPressMask|KeyReleaseMask)
74 #else
75 #define EVENT_MASK (LeaveWindowMask|EnterWindowMask|PropertyChangeMask\
76 |SubstructureNotifyMask|PointerMotionMask \
77 |SubstructureRedirectMask|ButtonPressMask|ButtonReleaseMask\
78 |KeyPressMask|KeyReleaseMask)
79 #endif
81 /**** Global variables ****/
83 extern Cursor wCursor[WCUR_LAST];
84 extern WPreferences wPreferences;
85 extern Atom _XA_WINDOWMAKER_STATE;
86 extern Atom _XA_WINDOWMAKER_NOTICEBOARD;
89 extern int wScreenCount;
91 extern WDDomain *WDWindowMaker;
94 /**** Local ****/
96 #define STIPPLE_WIDTH 2
97 #define STIPPLE_HEIGHT 2
98 static char STIPPLE_DATA[] = {0x02, 0x01};
100 static int CantManageScreen = 0;
102 static proplist_t dApplications = NULL;
103 static proplist_t dWorkspace;
104 static proplist_t dDock;
105 static proplist_t dClip;
108 static void
109 make_keys()
111 if (dApplications!=NULL)
112 return;
114 dApplications = PLMakeString("Applications");
115 dWorkspace = PLMakeString("Workspace");
116 dDock = PLMakeString("Dock");
117 dClip = PLMakeString("Clip");
122 *----------------------------------------------------------------------
123 * alreadyRunningError--
124 * X error handler used to catch errors when trying to do
125 * XSelectInput() on the root window. These errors probably mean that
126 * there already is some other window manager running.
128 * Returns:
129 * Nothing, unless something really evil happens...
131 * Side effects:
132 * CantManageScreen is set to 1;
133 *----------------------------------------------------------------------
135 static int
136 alreadyRunningError(Display *dpy, XErrorEvent *error)
138 CantManageScreen = 1;
139 return -1;
144 *----------------------------------------------------------------------
145 * allocButtonPixmaps--
146 * Allocate pixmaps used on window operation buttons (those in the
147 * titlebar). The pixmaps are linked to the program. If XPM is supported
148 * XPM pixmaps are used otherwise, equivalent bitmaps are used.
150 * Returns:
151 * Nothing
153 * Side effects:
154 * Allocates shared pixmaps for the screen. These pixmaps should
155 * not be freed by anybody.
156 *----------------------------------------------------------------------
158 static void
159 allocButtonPixmaps(WScreen *scr)
161 WPixmap *pix;
163 /* create predefined pixmaps */
164 pix = wPixmapCreateFromXPMData(scr, PRED_CLOSE_XPM);
165 if (pix)
166 pix->shared = 1;
167 scr->b_pixmaps[WBUT_CLOSE] = pix;
169 pix = wPixmapCreateFromXPMData(scr, PRED_BROKEN_CLOSE_XPM);
170 if (pix)
171 pix->shared = 1;
172 scr->b_pixmaps[WBUT_BROKENCLOSE] = pix;
174 pix = wPixmapCreateFromXPMData(scr, PRED_ICONIFY_XPM);
175 if (pix)
176 pix->shared = 1;
177 scr->b_pixmaps[WBUT_ICONIFY] = pix;
178 #ifdef XKB_BUTTON_HINT
179 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP1_XPM);
180 if (pix)
181 pix->shared = 1;
182 scr->b_pixmaps[WBUT_XKBGROUP1] = pix;
183 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP2_XPM);
184 if (pix)
185 pix->shared = 1;
186 scr->b_pixmaps[WBUT_XKBGROUP2] = pix;
187 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP3_XPM);
188 if (pix)
189 pix->shared = 1;
190 scr->b_pixmaps[WBUT_XKBGROUP3] = pix;
191 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP4_XPM);
192 if (pix)
193 pix->shared = 1;
194 scr->b_pixmaps[WBUT_XKBGROUP4] = pix;
195 #endif
198 pix = wPixmapCreateFromXPMData(scr, PRED_KILL_XPM);
199 if (pix)
200 pix->shared = 1;
201 scr->b_pixmaps[WBUT_KILL] = pix;
205 static void
206 draw_dot(WScreen *scr, Drawable d, int x, int y, GC gc)
208 XSetForeground(dpy, gc, scr->black_pixel);
209 XDrawLine(dpy, d, gc, x, y, x+1, y);
210 XDrawPoint(dpy, d, gc, x, y+1);
211 XSetForeground(dpy, gc, scr->white_pixel);
212 XDrawLine(dpy, d, gc, x+2, y, x+2, y+1);
213 XDrawPoint(dpy, d, gc, x+1, y+1);
217 static WPixmap*
218 make3Dots(WScreen *scr)
220 WPixmap *wpix;
221 GC gc2, gc;
222 XGCValues gcv;
223 Pixmap pix, mask;
225 gc = scr->copy_gc;
226 pix = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size,
227 wPreferences.icon_size, scr->w_depth);
228 XSetForeground(dpy, gc, scr->black_pixel);
229 XFillRectangle(dpy, pix, gc, 0, 0, wPreferences.icon_size,
230 wPreferences.icon_size);
231 XSetForeground(dpy, gc, scr->white_pixel);
232 draw_dot(scr, pix, 4, wPreferences.icon_size-6, gc);
233 draw_dot(scr, pix, 9, wPreferences.icon_size-6, gc);
234 draw_dot(scr, pix, 14, wPreferences.icon_size-6, gc);
236 mask = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size,
237 wPreferences.icon_size, 1);
238 gcv.foreground = 0;
239 gcv.graphics_exposures = False;
240 gc2 = XCreateGC(dpy, mask, GCForeground|GCGraphicsExposures, &gcv);
241 XFillRectangle(dpy, mask, gc2, 0, 0, wPreferences.icon_size,
242 wPreferences.icon_size);
243 XSetForeground(dpy, gc2, 1);
244 XFillRectangle(dpy, mask, gc2, 4, wPreferences.icon_size-6, 3, 2);
245 XFillRectangle(dpy, mask, gc2, 9, wPreferences.icon_size-6, 3, 2);
246 XFillRectangle(dpy, mask, gc2, 14, wPreferences.icon_size-6, 3, 2);
248 XFreeGC(dpy, gc2);
250 wpix = wPixmapCreate(scr, pix, mask);
251 wpix->shared = 1;
253 return wpix;
257 static void
258 allocGCs(WScreen *scr)
260 XGCValues gcv;
261 XColor color;
262 unsigned long mtextcolor;
263 int gcm;
265 scr->stipple_bitmap =
266 XCreateBitmapFromData(dpy, scr->w_win, STIPPLE_DATA, STIPPLE_WIDTH,
267 STIPPLE_HEIGHT);
269 gcv.stipple = scr->stipple_bitmap;
270 gcv.foreground = scr->white_pixel;
271 gcv.fill_style = FillStippled;
272 gcv.graphics_exposures = False;
273 gcm = GCForeground|GCStipple|GCFillStyle|GCGraphicsExposures;
274 scr->stipple_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
277 /* selected icon border GCs */
278 gcv.function = GXcopy;
279 gcv.foreground = scr->white_pixel;
280 gcv.background = scr->black_pixel;
281 gcv.line_width = 1;
282 gcv.line_style = LineDoubleDash;
283 gcv.fill_style = FillSolid;
284 gcv.dash_offset = 0;
285 gcv.dashes = 4;
286 gcv.graphics_exposures = False;
288 gcm = GCFunction | GCGraphicsExposures;
289 gcm |= GCForeground | GCBackground;
290 gcm |= GCLineWidth | GCLineStyle;
291 gcm |= GCFillStyle;
292 gcm |= GCDashOffset | GCDashList;
294 scr->icon_select_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
296 gcm = GCForeground|GCGraphicsExposures;
298 scr->menu_title_pixel[0] = scr->white_pixel;
299 gcv.foreground = scr->white_pixel;
300 gcv.graphics_exposures = False;
301 scr->menu_title_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
303 scr->mtext_pixel = scr->black_pixel;
304 mtextcolor = gcv.foreground = scr->black_pixel;
305 scr->menu_entry_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
307 /* selected menu entry GC */
308 gcm = GCForeground|GCBackground|GCGraphicsExposures;
309 gcv.foreground = scr->white_pixel;
310 gcv.background = scr->white_pixel;
311 gcv.graphics_exposures = False;
312 scr->select_menu_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
314 /* disabled menu entry GC */
315 scr->dtext_pixel = scr->black_pixel;
316 gcm = GCForeground|GCBackground|GCStipple|GCGraphicsExposures;
317 gcv.stipple = scr->stipple_bitmap;
318 gcv.graphics_exposures = False;
319 scr->disabled_menu_entry_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
321 /* frame GC */
322 wGetColor(scr, DEF_FRAME_COLOR, &color);
323 gcv.function = GXxor;
324 /* this will raise the probability of the XORed color being different
325 * of the original color in PseudoColor when not all color cells are
326 * initialized */
327 if (DefaultVisual(dpy, scr->screen)->class==PseudoColor)
328 gcv.plane_mask = (1<<(scr->depth-1))|1;
329 else
330 gcv.plane_mask = AllPlanes;
331 gcv.foreground = color.pixel;
332 if (gcv.foreground == 0)
333 gcv.foreground = 1;
334 gcv.line_width = DEF_FRAME_THICKNESS;
335 gcv.subwindow_mode = IncludeInferiors;
336 gcv.graphics_exposures = False;
337 scr->frame_gc = XCreateGC(dpy, scr->root_win, GCForeground|GCGraphicsExposures
338 |GCFunction|GCSubwindowMode|GCLineWidth
339 |GCPlaneMask, &gcv);
341 /* line GC */
342 gcv.foreground = color.pixel;
344 if (gcv.foreground == 0)
345 /* XOR:ing with a zero is not going to be of much use, so
346 in that case, we somewhat arbitrarily xor with 17 instead. */
347 gcv.foreground = 17;
349 gcv.function = GXxor;
350 gcv.subwindow_mode = IncludeInferiors;
351 gcv.line_width = 1;
352 gcv.cap_style = CapRound;
353 gcv.graphics_exposures = False;
354 gcm = GCForeground|GCFunction|GCSubwindowMode|GCLineWidth|GCCapStyle
355 |GCGraphicsExposures;
356 scr->line_gc = XCreateGC(dpy, scr->root_win, gcm, &gcv);
358 scr->line_pixel = gcv.foreground;
360 /* copy GC */
361 gcv.foreground = scr->white_pixel;
362 gcv.background = scr->black_pixel;
363 gcv.graphics_exposures = False;
364 scr->copy_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
365 |GCGraphicsExposures, &gcv);
367 /* window title text GC */
368 gcv.graphics_exposures = False;
369 scr->window_title_gc = XCreateGC(dpy, scr->w_win,GCGraphicsExposures,&gcv);
371 /* icon title GC */
372 scr->icon_title_gc = XCreateGC(dpy, scr->w_win, GCGraphicsExposures, &gcv);
374 /* clip title GC */
375 scr->clip_title_gc = XCreateGC(dpy, scr->w_win, GCGraphicsExposures, &gcv);
377 /* move/size display GC */
378 gcv.graphics_exposures = False;
379 gcm = GCGraphicsExposures;
380 scr->info_text_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
382 /* misc drawing GC */
383 gcv.graphics_exposures = False;
384 gcm = GCGraphicsExposures;
385 scr->draw_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
387 assert (scr->stipple_bitmap!=None);
390 /* mono GC */
391 scr->mono_gc = XCreateGC(dpy, scr->stipple_bitmap, gcm, &gcv);
396 static void
397 createPixmaps(WScreen *scr)
399 WPixmap *pix;
400 WMPixmap *wmpix;
401 RImage *image;
402 Pixmap p, m;
404 /* load pixmaps */
405 pix = wPixmapCreateFromXBMData(scr, (char*)MENU_RADIO_INDICATOR_XBM_DATA,
406 (char*)MENU_RADIO_INDICATOR_XBM_DATA,
407 MENU_RADIO_INDICATOR_XBM_SIZE,
408 MENU_RADIO_INDICATOR_XBM_SIZE,
409 scr->black_pixel, scr->white_pixel);
410 if (pix!=NULL)
411 pix->shared = 1;
412 scr->menu_radio_indicator = pix;
415 pix = wPixmapCreateFromXBMData(scr, (char*)MENU_CHECK_INDICATOR_XBM_DATA,
416 (char*)MENU_CHECK_INDICATOR_XBM_DATA,
417 MENU_CHECK_INDICATOR_XBM_SIZE,
418 MENU_CHECK_INDICATOR_XBM_SIZE,
419 scr->black_pixel, scr->white_pixel);
420 if (pix!=NULL)
421 pix->shared = 1;
422 scr->menu_check_indicator = pix;
424 pix = wPixmapCreateFromXBMData(scr, (char*)MENU_MINI_INDICATOR_XBM_DATA,
425 (char*)MENU_MINI_INDICATOR_XBM_DATA,
426 MENU_MINI_INDICATOR_XBM_SIZE,
427 MENU_MINI_INDICATOR_XBM_SIZE,
428 scr->black_pixel, scr->white_pixel);
429 if (pix!=NULL)
430 pix->shared = 1;
431 scr->menu_mini_indicator = pix;
433 pix = wPixmapCreateFromXBMData(scr, (char*)MENU_HIDE_INDICATOR_XBM_DATA,
434 (char*)MENU_HIDE_INDICATOR_XBM_DATA,
435 MENU_HIDE_INDICATOR_XBM_SIZE,
436 MENU_HIDE_INDICATOR_XBM_SIZE,
437 scr->black_pixel, scr->white_pixel);
438 if (pix!=NULL)
439 pix->shared = 1;
440 scr->menu_hide_indicator = pix;
442 pix = wPixmapCreateFromXBMData(scr, (char*)MENU_SHADE_INDICATOR_XBM_DATA,
443 (char*)MENU_SHADE_INDICATOR_XBM_DATA,
444 MENU_SHADE_INDICATOR_XBM_SIZE,
445 MENU_SHADE_INDICATOR_XBM_SIZE,
446 scr->black_pixel, scr->white_pixel);
447 if (pix!=NULL)
448 pix->shared = 1;
449 scr->menu_shade_indicator = pix;
452 image = wDefaultGetImage(scr, "Logo", "WMPanel");
454 if (!image) {
455 wwarning(_("could not load logo image for panels: %s"),
456 RMessageForError(RErrorCode));
457 } else {
458 if (!RConvertImageMask(scr->rcontext, image, &p, &m, 128)) {
459 wwarning(_("error making logo image for panel:%s"), RMessageForError(RErrorCode));
460 } else {
461 wmpix = WMCreatePixmapFromXPixmaps(scr->wmscreen, p, m,
462 image->width, image->height,
463 scr->depth);
464 WMSetApplicationIconImage(scr->wmscreen, wmpix);
465 WMReleasePixmap(wmpix);
467 RDestroyImage(image);
470 scr->dock_dots = make3Dots(scr);
472 #ifndef NEWSTUFF
473 /* titlebar button pixmaps */
474 allocButtonPixmaps(scr);
475 #endif
480 *----------------------------------------------------------------------
481 * createInternalWindows--
482 * Creates some windows used internally by the program. One to
483 * receive input focus when no other window can get it and another
484 * to display window geometry information during window resize/move.
486 * Returns:
487 * Nothing
489 * Side effects:
490 * Windows are created and some colors are allocated for the
491 * window background.
492 *----------------------------------------------------------------------
494 static void
495 createInternalWindows(WScreen *scr)
497 int vmask;
498 XSetWindowAttributes attribs;
500 /* window for displaying geometry information during resizes and moves */
501 vmask = CWBorderPixel|CWBackPixmap|CWBackPixel|CWCursor|CWSaveUnder|CWOverrideRedirect;
502 attribs.border_pixel = 0;
503 attribs.save_under = True;
504 attribs.override_redirect = True;
505 attribs.cursor = wCursor[WCUR_DEFAULT];
506 attribs.background_pixmap = None;
507 if (scr->widget_texture)
508 attribs.background_pixel = scr->widget_texture->normal.pixel;
509 else
510 attribs.background_pixel = scr->light_pixel;
511 vmask |= CWColormap;
512 attribs.colormap = scr->w_colormap;
514 wGetGeometryWindowSize(scr, &scr->geometry_display_width,
515 &scr->geometry_display_height);
516 scr->geometry_display =
517 XCreateWindow(dpy, scr->root_win, 1, 1,
518 scr->geometry_display_width,
519 scr->geometry_display_height,
520 1, scr->w_depth, CopyFromParent, scr->w_visual,
521 vmask, &attribs);
523 /* InputOnly window to get the focus when no other window can get it */
524 vmask = CWEventMask|CWOverrideRedirect;
525 attribs.event_mask = KeyPressMask|FocusChangeMask;
526 attribs.override_redirect = True;
527 scr->no_focus_win=XCreateWindow(dpy,scr->root_win,-10, -10, 4, 4, 0, 0,
528 InputOnly,CopyFromParent, vmask, &attribs);
529 XSelectInput(dpy, scr->no_focus_win, KeyPressMask|KeyReleaseMask);
530 XMapWindow(dpy, scr->no_focus_win);
532 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
534 /* shadow window for dock buttons */
535 vmask = CWBorderPixel|CWBackPixmap|CWBackPixel|CWCursor|CWSaveUnder|CWOverrideRedirect;
536 attribs.border_pixel = 0;
537 attribs.save_under = True;
538 attribs.override_redirect = True;
539 attribs.background_pixmap = None;
540 attribs.background_pixel = scr->white_pixel;
541 vmask |= CWColormap;
542 attribs.colormap = scr->w_colormap;
543 scr->dock_shadow =
544 XCreateWindow(dpy, scr->root_win, 0, 0, wPreferences.icon_size,
545 wPreferences.icon_size, 0, scr->w_depth, CopyFromParent,
546 scr->w_visual, vmask, &attribs);
548 /* workspace name balloon for clip */
549 vmask = CWBackPixel|CWSaveUnder|CWOverrideRedirect|CWColormap
550 |CWBorderPixel;
551 attribs.save_under = True;
552 attribs.override_redirect = True;
553 attribs.colormap = scr->w_colormap;
554 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
555 attribs.border_pixel = 0; /* do not care */
556 scr->clip_balloon =
557 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
558 CopyFromParent, scr->w_visual, vmask, &attribs);
561 /* workspace name */
562 vmask = CWBackPixel|CWSaveUnder|CWOverrideRedirect|CWColormap
563 |CWBorderPixel;
564 attribs.save_under = True;
565 attribs.override_redirect = True;
566 attribs.colormap = scr->w_colormap;
567 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
568 attribs.border_pixel = 0; /* do not care */
569 scr->workspace_name =
570 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
571 CopyFromParent, scr->w_visual, vmask, &attribs);
574 /* for our window manager info notice board */
575 scr->info_window =
576 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, CopyFromParent,
577 CopyFromParent, CopyFromParent, CWOverrideRedirect,
578 &attribs);
581 * If the window is clicked without having ButtonPress selected, the
582 * resulting event will have event.xbutton.window == root.
584 XSelectInput(dpy, scr->clip_balloon, ButtonPressMask);
588 #if 0
589 static Bool
590 aquireManagerSelection(WScreen *scr)
592 char buffer[32];
593 XEvent ev;
594 Time timestamp;
596 sprintf(buffer, "WM_S%i", scr->screen);
597 scr->managerAtom = XInternAtom(dpy, buffer, False);
599 /* for race-conditions... */
600 XGrabServer(dpy);
602 /* if there is another manager running, don't try to replace it
603 * (for now, at least) */
604 if (XGetSelectionOwner(dpy, scr->managerAtom) != None) {
605 XUngrabServer(dpy);
606 return False;
609 /* become the manager for this screen */
611 scr->managerWindow = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 1, 1,
612 0, 0, 0);
614 XSelectInput(dpy, scr->managerWindow, PropertyChangeMask);
615 /* get a timestamp */
616 XChangeProperty(dpy, scr->managerWindow, scr->managerAtom,
617 XA_INTEGER, 32, PropModeAppend, NULL, 0);
618 while (1) {
619 XWindowEvent(dpy, scr->managerWindow, &ev);
620 if (ev.type == PropertyNotify) {
621 timestamp = ev.xproperty.time;
622 break;
625 XSelectInput(dpy, scr->managerWindow, NoEvents);
626 XDeleteProperty(dpy, scr->managerWindow, scr->managerAtom);
628 XSetSelectionOwner(dpy, scr->managerAtom, scr->managerWindow, CurrentTime);
630 XUngrabServer(dpy);
632 /* announce our arrival */
634 ev.xclient.type = ClientMessage;
635 ev.xclient.message_type = XInternAtom(dpy, "MANAGER", False);
636 ev.xclient.destination = scr->root_win;
637 ev.xclient.format = 32;
638 ev.xclient.data.l[0] = timestamp;
639 ev.xclient.data.l[1] = scr->managerAtom;
640 ev.xclient.data.l[2] = scr->managerWindow;
641 ev.xclient.data.l[3] = 0;
642 ev.xclient.data.l[4] = 0;
644 XSendEvent(dpy, scr->root_win, False, StructureNotify, &ev);
645 XSync(dpy, False);
647 return True;
649 #endif
652 *----------------------------------------------------------------------
653 * wScreenInit--
654 * Initializes the window manager for the given screen and
655 * allocates a WScreen descriptor for it. Many resources are allocated
656 * for the screen and the root window is setup appropriately.
658 * Returns:
659 * The WScreen descriptor for the screen.
661 * Side effects:
662 * Many resources are allocated and the IconSize property is
663 * set on the root window.
664 * The program can be aborted if some fatal error occurs.
666 * TODO: User specifiable visual.
667 *----------------------------------------------------------------------
669 WScreen*
670 wScreenInit(int screen_number)
672 WScreen *scr;
673 XIconSize icon_size[1];
674 RContextAttributes rattr;
675 extern int wVisualID;
676 long event_mask;
677 WMColor *color;
678 XErrorHandler oldHandler;
680 scr = wmalloc(sizeof(WScreen));
681 memset(scr, 0, sizeof(WScreen));
683 /* initialize globals */
684 scr->screen = screen_number;
685 scr->root_win = RootWindow(dpy, screen_number);
686 scr->depth = DefaultDepth(dpy, screen_number);
687 scr->colormap = DefaultColormap(dpy, screen_number);
689 scr->scr_width = WidthOfScreen(ScreenOfDisplay(dpy, screen_number));
690 scr->scr_height = HeightOfScreen(ScreenOfDisplay(dpy, screen_number));
692 scr->usableArea.x2 = scr->scr_width;
693 scr->usableArea.y2 = scr->scr_height;
694 scr->totalUsableArea.x2 = scr->scr_width;
695 scr->totalUsableArea.y2 = scr->scr_height;
697 #if 0
698 if (!aquireManagerSelection(scr)) {
699 free(scr);
701 return NULL;
703 #endif
704 CantManageScreen = 0;
705 oldHandler = XSetErrorHandler((XErrorHandler)alreadyRunningError);
707 event_mask = EVENT_MASK;
709 if (wPreferences.disable_root_mouse) {
710 event_mask &= ~(ButtonPressMask|ButtonReleaseMask);
713 XSelectInput(dpy, scr->root_win, event_mask);
715 #ifdef KEEP_XKB_LOCK_STATUS
716 XkbSelectEventDetails(dpy,XkbUseCoreKbd,XkbIndicatorStateNotify,
717 XkbIndicatorStateNotifyMask, XkbIndicatorStateNotifyMask);
718 #endif /* KEEP_XKB_LOCK_STATUS */
720 XSync(dpy, False);
721 XSetErrorHandler(oldHandler);
723 if (CantManageScreen) {
724 free(scr);
725 return NULL;
728 XDefineCursor(dpy, scr->root_win, wCursor[WCUR_DEFAULT]);
730 /* screen descriptor for raster graphic library */
731 rattr.flags = RC_RenderMode | RC_ColorsPerChannel;
732 rattr.render_mode = wPreferences.no_dithering
733 ? RBestMatchRendering
734 : RDitheredRendering;
736 rattr.colors_per_channel = wPreferences.cmap_size;
737 if (rattr.colors_per_channel<2)
738 rattr.colors_per_channel = 2;
740 if (wVisualID>=0) {
741 rattr.flags |= RC_VisualID;
742 rattr.visualid = wVisualID;
744 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
745 if (!scr->rcontext) {
746 wwarning(_("could not initialize graphics library context: %s"),
747 RMessageForError(RErrorCode));
748 wAbort(False);
749 } else {
750 char **formats;
751 int i = 0;
753 formats = RSupportedFileFormats();
754 if (formats) {
755 for (i=0; formats[i]!=NULL; i++) {
756 if (strcmp(formats[i], "TIFF")==0) {
757 scr->flags.supports_tiff = 1;
758 break;
764 scr->w_win = scr->rcontext->drawable;
765 scr->w_visual = scr->rcontext->visual;
766 scr->w_depth = scr->rcontext->depth;
767 scr->w_colormap = scr->rcontext->cmap;
769 scr->black_pixel = scr->rcontext->black;
770 scr->white_pixel = scr->rcontext->white;
772 /* create screen descriptor for WINGs */
773 scr->wmscreen = WMCreateScreenWithRContext(dpy, screen_number,
774 scr->rcontext);
776 if (!scr->wmscreen) {
777 wfatal(_("could not do initialization of WINGs widget set"));
779 return NULL;
782 color = WMGrayColor(scr->wmscreen);
783 scr->light_pixel = WMColorPixel(color);
784 WMReleaseColor(color);
786 color = WMDarkGrayColor(scr->wmscreen);
787 scr->dark_pixel = WMColorPixel(color);
788 WMReleaseColor(color);
791 XColor xcol;
792 /* frame boder color */
793 wGetColor(scr, FRAME_BORDER_COLOR, &xcol);
794 scr->frame_border_pixel = xcol.pixel;
797 /* create GCs with default values */
798 allocGCs(scr);
800 /* read defaults for this screen */
801 wReadDefaults(scr, WDWindowMaker->dictionary);
803 createInternalWindows(scr);
805 #ifdef KWM_HINTS
806 wKWMInitStuff(scr);
807 #endif
809 #ifdef GNOME_STUFF
810 wGNOMEInitStuff(scr);
811 #endif
813 #ifdef OLWM_HINTS
814 wOLWMInitStuff(scr);
815 #endif
817 /* create initial workspace */
818 wWorkspaceNew(scr);
820 /* create shared pixmaps */
821 createPixmaps(scr);
823 /* set icon sizes we can accept from clients */
824 icon_size[0].min_width = 8;
825 icon_size[0].min_height = 8;
826 icon_size[0].max_width = wPreferences.icon_size-4;
827 icon_size[0].max_height = wPreferences.icon_size-4;
828 icon_size[0].width_inc = 1;
829 icon_size[0].height_inc = 1;
830 XSetIconSizes(dpy, scr->root_win, icon_size, 1);
832 /* setup WindowMaker protocols property in the root window*/
833 PropSetWMakerProtocols(scr->root_win);
835 /* setup our noticeboard */
836 XChangeProperty(dpy, scr->info_window, _XA_WINDOWMAKER_NOTICEBOARD,
837 XA_WINDOW, 32, PropModeReplace,
838 (unsigned char*)&scr->info_window, 1);
839 XChangeProperty(dpy, scr->root_win, _XA_WINDOWMAKER_NOTICEBOARD,
840 XA_WINDOW, 32, PropModeReplace,
841 (unsigned char*)&scr->info_window, 1);
844 #ifdef BALLOON_TEXT
845 /* initialize balloon text stuff */
846 wBalloonInitialize(scr);
847 #endif
849 wScreenUpdateUsableArea(scr);
851 #ifndef LITE
852 /* kluge to load menu configurations at startup */
853 OpenRootMenu(scr, -10000, -10000, False);
854 wMenuUnmap(scr->root_menu);
855 #endif
857 return scr;
861 void
862 wScreenUpdateUsableArea(WScreen *scr)
864 #ifdef GNOME_STUFF
865 WReservedArea *area;
866 #endif
868 scr->totalUsableArea = scr->usableArea;
871 if (scr->dock && (!scr->dock->lowered
872 || wPreferences.no_window_over_dock)) {
874 int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
876 if (scr->dock->on_right_side) {
877 scr->totalUsableArea.x2 = WMIN(scr->totalUsableArea.x2,
878 scr->scr_width - offset);
879 } else {
880 scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, offset);
884 if (wPreferences.no_window_over_icons) {
885 if (wPreferences.icon_yard & IY_VERT) {
887 if (!(wPreferences.icon_yard & IY_RIGHT)) {
888 scr->totalUsableArea.x1 += wPreferences.icon_size;
889 } else {
890 scr->totalUsableArea.x2 -= wPreferences.icon_size;
892 } else {
894 if (wPreferences.icon_yard & IY_TOP) {
895 scr->totalUsableArea.y1 += wPreferences.icon_size;
896 } else {
897 scr->totalUsableArea.y2 -= wPreferences.icon_size;
902 #ifdef KWM_HINTS
904 WArea area;
906 if (wKWMGetUsableArea(scr, &area)) {
907 scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, area.x1);
908 scr->totalUsableArea.y1 = WMAX(scr->totalUsableArea.y1, area.y1);
909 scr->totalUsableArea.x2 = WMIN(scr->totalUsableArea.x2, area.x2);
910 scr->totalUsableArea.y2 = WMIN(scr->totalUsableArea.y2, area.y2);
913 #endif
915 #ifdef GNOME_STUFF
916 area = scr->reservedAreas;
918 while (area) {
919 int th, bh;
920 int lw, rw;
921 int w, h;
923 w = area->area.x2 - area->area.x1;
924 h = area->area.y2 - area->area.y1;
926 th = area->area.y1;
927 bh = scr->scr_height - area->area.y2;
928 lw = area->area.x1;
929 rw = scr->scr_width - area->area.x2;
931 if (WMIN(th, bh) < WMIN(lw, rw)) {
932 /* horizontal */
933 if (th < bh) {
934 /* on top */
935 if (scr->totalUsableArea.y1 < area->area.y2)
936 scr->totalUsableArea.y1 = area->area.y2;
937 } else {
938 /* on bottom */
939 if (scr->totalUsableArea.y2 > area->area.y1)
940 scr->totalUsableArea.y2 = area->area.y1;
942 } else {
943 /* vertical */
944 if (lw < rw) {
945 /* on left */
946 if (scr->totalUsableArea.x1 < area->area.x2)
947 scr->totalUsableArea.x1 = area->area.x2;
948 } else {
949 /* on right */
950 if (scr->totalUsableArea.x2 > area->area.x1)
951 scr->totalUsableArea.x2 = area->area.x1;
955 area = area->next;
957 #endif /* GNOME_STUFF */
959 if (scr->totalUsableArea.x2 - scr->totalUsableArea.x1 < scr->scr_width/2) {
960 scr->totalUsableArea.x2 = scr->usableArea.x2;
961 scr->totalUsableArea.x1 = scr->usableArea.x1;
963 if (scr->totalUsableArea.y2 - scr->totalUsableArea.y1 < scr->scr_height/2) {
964 scr->totalUsableArea.y2 = scr->usableArea.y2;
965 scr->totalUsableArea.y1 = scr->usableArea.y1;
968 #ifdef not_used
969 #ifdef KWM_HINTS
971 int i;
973 for (i = 0; i < scr->workspace_count; i++) {
974 wKWMSetUsableAreaHint(scr, i);
977 #endif
978 #endif
982 void
983 wScreenRestoreState(WScreen *scr)
985 proplist_t state;
986 char *path;
988 make_keys();
990 if (wScreenCount == 1)
991 path = wdefaultspathfordomain("WMState");
992 else {
993 char buf[16];
994 sprintf(buf, "WMState.%i", scr->screen);
995 path = wdefaultspathfordomain(buf);
997 scr->session_state = PLGetProplistWithPath(path);
998 free(path);
999 if (!scr->session_state && wScreenCount>1) {
1000 char buf[16];
1001 sprintf(buf, "WMState.%i", scr->screen);
1002 path = wdefaultspathfordomain(buf);
1003 scr->session_state = PLGetProplistWithPath(path);
1004 free(path);
1007 if (!wPreferences.flags.noclip) {
1008 state = PLGetDictionaryEntry(scr->session_state, dClip);
1009 scr->clip_icon = wClipRestoreState(scr, state);
1012 wWorkspaceRestoreState(scr);
1014 if (!wPreferences.flags.nodock) {
1015 state = PLGetDictionaryEntry(scr->session_state, dDock);
1016 scr->dock = wDockRestoreState(scr, state, WM_DOCK);
1019 wScreenUpdateUsableArea(scr);
1023 void
1024 wScreenSaveState(WScreen *scr)
1026 WWorkspaceState wstate;
1027 WWindow *wwin;
1028 char *str;
1029 proplist_t path, old_state, foo;
1030 CARD32 data[2];
1033 make_keys();
1036 * Save current workspace, so can go back to it upon restart.
1038 wstate.workspace = scr->current_workspace;
1040 data[0] = wstate.flags;
1041 data[1] = wstate.workspace;
1043 XChangeProperty(dpy, scr->root_win, _XA_WINDOWMAKER_STATE,
1044 _XA_WINDOWMAKER_STATE, 32, PropModeReplace,
1045 (unsigned char *) data, 2);
1047 /* save state of windows */
1048 wwin = scr->focused_window;
1049 while (wwin) {
1050 wWindowSaveState(wwin);
1051 wwin = wwin->prev;
1055 if (wPreferences.flags.noupdates)
1056 return;
1059 old_state = scr->session_state;
1060 scr->session_state = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
1062 PLSetStringCmpHook(NULL);
1064 /* save dock state to file */
1065 if (!wPreferences.flags.nodock) {
1066 wDockSaveState(scr);
1067 } else {
1068 if ((foo = PLGetDictionaryEntry(old_state, dDock))!=NULL) {
1069 PLInsertDictionaryEntry(scr->session_state, dDock, foo);
1072 if (!wPreferences.flags.noclip) {
1073 wClipSaveState(scr);
1074 } else {
1075 if ((foo = PLGetDictionaryEntry(old_state, dClip))!=NULL) {
1076 PLInsertDictionaryEntry(scr->session_state, dClip, foo);
1080 wWorkspaceSaveState(scr, old_state);
1082 if (wPreferences.save_session_on_exit) {
1083 wSessionSaveState(scr);
1084 } else {
1085 if ((foo = PLGetDictionaryEntry(old_state, dApplications))!=NULL) {
1086 PLInsertDictionaryEntry(scr->session_state, dApplications, foo);
1088 if ((foo = PLGetDictionaryEntry(old_state, dWorkspace))!=NULL) {
1089 PLInsertDictionaryEntry(scr->session_state, dWorkspace, foo);
1093 /* clean up */
1094 PLSetStringCmpHook(StringCompareHook);
1096 wMenuSaveState(scr);
1098 if (wScreenCount == 1)
1099 str = wdefaultspathfordomain("WMState");
1100 else {
1101 char buf[16];
1102 sprintf(buf, "WMState.%i", scr->screen);
1103 str = wdefaultspathfordomain(buf);
1105 path = PLMakeString(str);
1106 free(str);
1107 PLSetFilename(scr->session_state, path);
1108 if (!PLSave(scr->session_state, YES)) {
1109 wsyserror(_("could not save session state in %s"), PLGetString(path));
1111 PLRelease(path);
1112 PLRelease(old_state);
1118 wScreenBringInside(WScreen *scr, int *x, int *y, int width, int height)
1120 int moved = 0;
1121 int tol_w, tol_h;
1123 if (width > 20)
1124 tol_w = width/2;
1125 else
1126 tol_w = 20;
1128 if (height > 20)
1129 tol_h = height/2;
1130 else
1131 tol_h = 20;
1133 if (*x+width < 10)
1134 *x = -tol_w, moved = 1;
1135 else if (*x >= scr->scr_width - 10)
1136 *x = scr->scr_width - tol_w - 1, moved = 1;
1138 if (*y < -height + 10)
1139 *y = -tol_h, moved = 1;
1140 else if (*y >= scr->scr_height - 10)
1141 *y = scr->scr_height - tol_h - 1, moved = 1;
1143 return moved;