- Added WMCreateNonAAFont() to WINGs
[wmaker-crm.git] / src / screen.c
blob6886bb38bafb4556e94d0d2d3b656a3a13f7caad
1 /* screen.c - screen management
2 *
3 * Window Maker window manager
4 *
5 * Copyright (c) 1997-2002 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 #include "geomview.h"
56 #ifdef KWM_HINTS
57 # include "kwm.h"
58 #endif
59 #ifdef GNOME_STUFF
60 # include "gnome.h"
61 #endif
62 #ifdef OLWM_HINTS
63 # include "openlook.h"
64 #endif
66 #include "xinerama.h"
68 #include <WINGs/WUtil.h>
70 #include "defaults.h"
73 #ifdef LITE
74 #define EVENT_MASK (LeaveWindowMask|EnterWindowMask|PropertyChangeMask\
75 |SubstructureNotifyMask|PointerMotionMask \
76 |SubstructureRedirectMask|KeyPressMask|KeyReleaseMask)
77 #else
78 #define EVENT_MASK (LeaveWindowMask|EnterWindowMask|PropertyChangeMask\
79 |SubstructureNotifyMask|PointerMotionMask \
80 |SubstructureRedirectMask|ButtonPressMask|ButtonReleaseMask\
81 |KeyPressMask|KeyReleaseMask)
82 #endif
84 /**** Global variables ****/
86 extern Cursor wCursor[WCUR_LAST];
87 extern WPreferences wPreferences;
88 extern Atom _XA_WINDOWMAKER_STATE;
89 extern Atom _XA_WINDOWMAKER_NOTICEBOARD;
92 extern int wScreenCount;
94 #ifdef KEEP_XKB_LOCK_STATUS
95 extern int wXkbSupported;
96 #endif
98 extern WDDomain *WDWindowMaker;
101 /**** Local ****/
103 #define STIPPLE_WIDTH 2
104 #define STIPPLE_HEIGHT 2
105 static char STIPPLE_DATA[] = {0x02, 0x01};
107 static int CantManageScreen = 0;
109 static WMPropList *dApplications = NULL;
110 static WMPropList *dWorkspace;
111 static WMPropList *dDock;
112 static WMPropList *dClip;
115 static void
116 make_keys()
118 if (dApplications!=NULL)
119 return;
121 dApplications = WMCreatePLString("Applications");
122 dWorkspace = WMCreatePLString("Workspace");
123 dDock = WMCreatePLString("Dock");
124 dClip = WMCreatePLString("Clip");
129 *----------------------------------------------------------------------
130 * alreadyRunningError--
131 * X error handler used to catch errors when trying to do
132 * XSelectInput() on the root window. These errors probably mean that
133 * there already is some other window manager running.
135 * Returns:
136 * Nothing, unless something really evil happens...
138 * Side effects:
139 * CantManageScreen is set to 1;
140 *----------------------------------------------------------------------
142 static int
143 alreadyRunningError(Display *dpy, XErrorEvent *error)
145 CantManageScreen = 1;
146 return -1;
151 *----------------------------------------------------------------------
152 * allocButtonPixmaps--
153 * Allocate pixmaps used on window operation buttons (those in the
154 * titlebar). The pixmaps are linked to the program. If XPM is supported
155 * XPM pixmaps are used otherwise, equivalent bitmaps are used.
157 * Returns:
158 * Nothing
160 * Side effects:
161 * Allocates shared pixmaps for the screen. These pixmaps should
162 * not be freed by anybody.
163 *----------------------------------------------------------------------
165 static void
166 allocButtonPixmaps(WScreen *scr)
168 WPixmap *pix;
170 /* create predefined pixmaps */
171 pix = wPixmapCreateFromXPMData(scr, PRED_CLOSE_XPM);
172 if (pix)
173 pix->shared = 1;
174 scr->b_pixmaps[WBUT_CLOSE] = pix;
176 pix = wPixmapCreateFromXPMData(scr, PRED_BROKEN_CLOSE_XPM);
177 if (pix)
178 pix->shared = 1;
179 scr->b_pixmaps[WBUT_BROKENCLOSE] = pix;
181 pix = wPixmapCreateFromXPMData(scr, PRED_ICONIFY_XPM);
182 if (pix)
183 pix->shared = 1;
184 scr->b_pixmaps[WBUT_ICONIFY] = pix;
185 #ifdef XKB_BUTTON_HINT
186 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP1_XPM);
187 if (pix)
188 pix->shared = 1;
189 scr->b_pixmaps[WBUT_XKBGROUP1] = pix;
190 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP2_XPM);
191 if (pix)
192 pix->shared = 1;
193 scr->b_pixmaps[WBUT_XKBGROUP2] = pix;
194 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP3_XPM);
195 if (pix)
196 pix->shared = 1;
197 scr->b_pixmaps[WBUT_XKBGROUP3] = pix;
198 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP4_XPM);
199 if (pix)
200 pix->shared = 1;
201 scr->b_pixmaps[WBUT_XKBGROUP4] = pix;
202 #endif
205 pix = wPixmapCreateFromXPMData(scr, PRED_KILL_XPM);
206 if (pix)
207 pix->shared = 1;
208 scr->b_pixmaps[WBUT_KILL] = pix;
212 static void
213 draw_dot(WScreen *scr, Drawable d, int x, int y, GC gc)
215 XSetForeground(dpy, gc, scr->black_pixel);
216 XDrawLine(dpy, d, gc, x, y, x+1, y);
217 XDrawPoint(dpy, d, gc, x, y+1);
218 XSetForeground(dpy, gc, scr->white_pixel);
219 XDrawLine(dpy, d, gc, x+2, y, x+2, y+1);
220 XDrawPoint(dpy, d, gc, x+1, y+1);
224 static WPixmap*
225 make3Dots(WScreen *scr)
227 WPixmap *wpix;
228 GC gc2, gc;
229 XGCValues gcv;
230 Pixmap pix, mask;
232 gc = scr->copy_gc;
233 pix = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size,
234 wPreferences.icon_size, scr->w_depth);
235 XSetForeground(dpy, gc, scr->black_pixel);
236 XFillRectangle(dpy, pix, gc, 0, 0, wPreferences.icon_size,
237 wPreferences.icon_size);
238 XSetForeground(dpy, gc, scr->white_pixel);
239 draw_dot(scr, pix, 4, wPreferences.icon_size-6, gc);
240 draw_dot(scr, pix, 9, wPreferences.icon_size-6, gc);
241 draw_dot(scr, pix, 14, wPreferences.icon_size-6, gc);
243 mask = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size,
244 wPreferences.icon_size, 1);
245 gcv.foreground = 0;
246 gcv.graphics_exposures = False;
247 gc2 = XCreateGC(dpy, mask, GCForeground|GCGraphicsExposures, &gcv);
248 XFillRectangle(dpy, mask, gc2, 0, 0, wPreferences.icon_size,
249 wPreferences.icon_size);
250 XSetForeground(dpy, gc2, 1);
251 XFillRectangle(dpy, mask, gc2, 4, wPreferences.icon_size-6, 3, 2);
252 XFillRectangle(dpy, mask, gc2, 9, wPreferences.icon_size-6, 3, 2);
253 XFillRectangle(dpy, mask, gc2, 14, wPreferences.icon_size-6, 3, 2);
255 XFreeGC(dpy, gc2);
257 wpix = wPixmapCreate(scr, pix, mask);
258 wpix->shared = 1;
260 return wpix;
264 static void
265 allocGCs(WScreen *scr)
267 XGCValues gcv;
268 XColor color;
269 int gcm;
271 scr->stipple_bitmap =
272 XCreateBitmapFromData(dpy, scr->w_win, STIPPLE_DATA, STIPPLE_WIDTH,
273 STIPPLE_HEIGHT);
275 gcv.stipple = scr->stipple_bitmap;
276 gcv.foreground = scr->white_pixel;
277 gcv.fill_style = FillStippled;
278 gcv.graphics_exposures = False;
279 gcm = GCForeground|GCStipple|GCFillStyle|GCGraphicsExposures;
280 scr->stipple_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
283 /* selected icon border GCs */
284 gcv.function = GXcopy;
285 gcv.foreground = scr->white_pixel;
286 gcv.background = scr->black_pixel;
287 gcv.line_width = 1;
288 gcv.line_style = LineDoubleDash;
289 gcv.fill_style = FillSolid;
290 gcv.dash_offset = 0;
291 gcv.dashes = 4;
292 gcv.graphics_exposures = False;
294 gcm = GCFunction | GCGraphicsExposures;
295 gcm |= GCForeground | GCBackground;
296 gcm |= GCLineWidth | GCLineStyle;
297 gcm |= GCFillStyle;
298 gcm |= GCDashOffset | GCDashList;
300 scr->icon_select_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
302 scr->menu_title_color[0] = WMRetainColor(scr->white);
304 /* don't retain scr->black here because we may alter its alpha */
305 scr->mtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
306 scr->dtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
308 /* frame GC */
309 wGetColor(scr, DEF_FRAME_COLOR, &color);
310 gcv.function = GXxor;
311 /* this will raise the probability of the XORed color being different
312 * of the original color in PseudoColor when not all color cells are
313 * initialized */
314 if (DefaultVisual(dpy, scr->screen)->class==PseudoColor)
315 gcv.plane_mask = (1<<(scr->depth-1))|1;
316 else
317 gcv.plane_mask = AllPlanes;
318 gcv.foreground = color.pixel;
319 if (gcv.foreground == 0)
320 gcv.foreground = 1;
321 gcv.line_width = DEF_FRAME_THICKNESS;
322 gcv.subwindow_mode = IncludeInferiors;
323 gcv.graphics_exposures = False;
324 scr->frame_gc = XCreateGC(dpy, scr->root_win, GCForeground|GCGraphicsExposures
325 |GCFunction|GCSubwindowMode|GCLineWidth
326 |GCPlaneMask, &gcv);
328 /* line GC */
329 gcv.foreground = color.pixel;
331 if (gcv.foreground == 0)
332 /* XOR:ing with a zero is not going to be of much use, so
333 in that case, we somewhat arbitrarily xor with 17 instead. */
334 gcv.foreground = 17;
336 gcv.function = GXxor;
337 gcv.subwindow_mode = IncludeInferiors;
338 gcv.line_width = 1;
339 gcv.cap_style = CapRound;
340 gcv.graphics_exposures = False;
341 gcm = GCForeground|GCFunction|GCSubwindowMode|GCLineWidth|GCCapStyle
342 |GCGraphicsExposures;
343 scr->line_gc = XCreateGC(dpy, scr->root_win, gcm, &gcv);
345 scr->line_pixel = gcv.foreground;
347 /* copy GC */
348 gcv.foreground = scr->white_pixel;
349 gcv.background = scr->black_pixel;
350 gcv.graphics_exposures = False;
351 scr->copy_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
352 |GCGraphicsExposures, &gcv);
354 /* clip title GC */
355 scr->clip_title_gc = XCreateGC(dpy, scr->w_win, GCGraphicsExposures, &gcv);
357 /* move/size display GC */
358 gcv.graphics_exposures = False;
359 gcm = GCGraphicsExposures;
360 scr->info_text_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
362 /* misc drawing GC */
363 gcv.graphics_exposures = False;
364 gcm = GCGraphicsExposures;
365 scr->draw_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
367 assert (scr->stipple_bitmap!=None);
370 /* mono GC */
371 scr->mono_gc = XCreateGC(dpy, scr->stipple_bitmap, gcm, &gcv);
376 static void
377 createPixmaps(WScreen *scr)
379 WPixmap *pix;
380 RImage *image;
382 /* load pixmaps */
383 pix = wPixmapCreateFromXBMData(scr, (char*)MENU_RADIO_INDICATOR_XBM_DATA,
384 (char*)MENU_RADIO_INDICATOR_XBM_DATA,
385 MENU_RADIO_INDICATOR_XBM_SIZE,
386 MENU_RADIO_INDICATOR_XBM_SIZE,
387 scr->black_pixel, scr->white_pixel);
388 if (pix!=NULL)
389 pix->shared = 1;
390 scr->menu_radio_indicator = pix;
393 pix = wPixmapCreateFromXBMData(scr, (char*)MENU_CHECK_INDICATOR_XBM_DATA,
394 (char*)MENU_CHECK_INDICATOR_XBM_DATA,
395 MENU_CHECK_INDICATOR_XBM_SIZE,
396 MENU_CHECK_INDICATOR_XBM_SIZE,
397 scr->black_pixel, scr->white_pixel);
398 if (pix!=NULL)
399 pix->shared = 1;
400 scr->menu_check_indicator = pix;
402 pix = wPixmapCreateFromXBMData(scr, (char*)MENU_MINI_INDICATOR_XBM_DATA,
403 (char*)MENU_MINI_INDICATOR_XBM_DATA,
404 MENU_MINI_INDICATOR_XBM_SIZE,
405 MENU_MINI_INDICATOR_XBM_SIZE,
406 scr->black_pixel, scr->white_pixel);
407 if (pix!=NULL)
408 pix->shared = 1;
409 scr->menu_mini_indicator = pix;
411 pix = wPixmapCreateFromXBMData(scr, (char*)MENU_HIDE_INDICATOR_XBM_DATA,
412 (char*)MENU_HIDE_INDICATOR_XBM_DATA,
413 MENU_HIDE_INDICATOR_XBM_SIZE,
414 MENU_HIDE_INDICATOR_XBM_SIZE,
415 scr->black_pixel, scr->white_pixel);
416 if (pix!=NULL)
417 pix->shared = 1;
418 scr->menu_hide_indicator = pix;
420 pix = wPixmapCreateFromXBMData(scr, (char*)MENU_SHADE_INDICATOR_XBM_DATA,
421 (char*)MENU_SHADE_INDICATOR_XBM_DATA,
422 MENU_SHADE_INDICATOR_XBM_SIZE,
423 MENU_SHADE_INDICATOR_XBM_SIZE,
424 scr->black_pixel, scr->white_pixel);
425 if (pix!=NULL)
426 pix->shared = 1;
427 scr->menu_shade_indicator = pix;
430 image = wDefaultGetImage(scr, "Logo", "WMPanel");
432 if (!image) {
433 wwarning(_("could not load logo image for panels: %s"),
434 RMessageForError(RErrorCode));
435 } else {
436 WMSetApplicationIconImage(scr->wmscreen, image);
437 RReleaseImage(image);
440 scr->dock_dots = make3Dots(scr);
442 /* titlebar button pixmaps */
443 allocButtonPixmaps(scr);
448 *----------------------------------------------------------------------
449 * createInternalWindows--
450 * Creates some windows used internally by the program. One to
451 * receive input focus when no other window can get it and another
452 * to display window geometry information during window resize/move.
454 * Returns:
455 * Nothing
457 * Side effects:
458 * Windows are created and some colors are allocated for the
459 * window background.
460 *----------------------------------------------------------------------
462 static void
463 createInternalWindows(WScreen *scr)
465 int vmask;
466 XSetWindowAttributes attribs;
468 /* InputOnly window to get the focus when no other window can get it */
469 vmask = CWEventMask|CWOverrideRedirect;
470 attribs.event_mask = KeyPressMask|FocusChangeMask;
471 attribs.override_redirect = True;
472 scr->no_focus_win=XCreateWindow(dpy,scr->root_win,-10, -10, 4, 4, 0, 0,
473 InputOnly,CopyFromParent, vmask, &attribs);
474 XSelectInput(dpy, scr->no_focus_win, KeyPressMask|KeyReleaseMask);
475 XMapWindow(dpy, scr->no_focus_win);
477 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
479 /* shadow window for dock buttons */
480 vmask = CWBorderPixel|CWBackPixmap|CWBackPixel|CWCursor|CWSaveUnder|CWOverrideRedirect;
481 attribs.border_pixel = scr->black_pixel;
482 attribs.save_under = True;
483 attribs.override_redirect = True;
484 attribs.background_pixmap = None;
485 attribs.background_pixel = scr->white_pixel;
486 attribs.cursor = wCursor[WCUR_DEFAULT];
487 vmask |= CWColormap;
488 attribs.colormap = scr->w_colormap;
489 scr->dock_shadow =
490 XCreateWindow(dpy, scr->root_win, 0, 0, wPreferences.icon_size,
491 wPreferences.icon_size, 0, scr->w_depth, CopyFromParent,
492 scr->w_visual, vmask, &attribs);
494 /* workspace name balloon for clip */
495 vmask = CWBackPixel|CWSaveUnder|CWOverrideRedirect|CWColormap
496 |CWBorderPixel;
497 attribs.save_under = True;
498 attribs.override_redirect = True;
499 attribs.colormap = scr->w_colormap;
500 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
501 attribs.border_pixel = 0; /* do not care */
502 scr->clip_balloon =
503 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
504 CopyFromParent, scr->w_visual, vmask, &attribs);
507 /* workspace name */
508 vmask = CWBackPixel|CWSaveUnder|CWOverrideRedirect|CWColormap
509 |CWBorderPixel;
510 attribs.save_under = True;
511 attribs.override_redirect = True;
512 attribs.colormap = scr->w_colormap;
513 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
514 attribs.border_pixel = 0; /* do not care */
515 scr->workspace_name =
516 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
517 CopyFromParent, scr->w_visual, vmask, &attribs);
520 * If the window is clicked without having ButtonPress selected, the
521 * resulting event will have event.xbutton.window == root.
523 XSelectInput(dpy, scr->clip_balloon, ButtonPressMask);
527 #if 0
528 static Bool
529 aquireManagerSelection(WScreen *scr)
531 char buffer[32];
532 XEvent ev;
533 Time timestamp;
535 snprintf(buffer, sizeof(buffer), "WM_S%i", scr->screen);
536 scr->managerAtom = XInternAtom(dpy, buffer, False);
538 /* for race-conditions... */
539 XGrabServer(dpy);
541 /* if there is another manager running, don't try to replace it
542 * (for now, at least) */
543 if (XGetSelectionOwner(dpy, scr->managerAtom) != None) {
544 XUngrabServer(dpy);
545 return False;
548 /* become the manager for this screen */
550 scr->managerWindow = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 1, 1,
551 0, 0, 0);
553 XSelectInput(dpy, scr->managerWindow, PropertyChangeMask);
554 /* get a timestamp */
555 XChangeProperty(dpy, scr->managerWindow, scr->managerAtom,
556 XA_INTEGER, 32, PropModeAppend, NULL, 0);
557 while (1) {
558 XWindowEvent(dpy, scr->managerWindow, &ev);
559 if (ev.type == PropertyNotify) {
560 timestamp = ev.xproperty.time;
561 break;
564 XSelectInput(dpy, scr->managerWindow, NoEvents);
565 XDeleteProperty(dpy, scr->managerWindow, scr->managerAtom);
567 XSetSelectionOwner(dpy, scr->managerAtom, scr->managerWindow, CurrentTime);
569 XUngrabServer(dpy);
571 /* announce our arrival */
573 ev.xclient.type = ClientMessage;
574 ev.xclient.message_type = XInternAtom(dpy, "MANAGER", False);
575 ev.xclient.destination = scr->root_win;
576 ev.xclient.format = 32;
577 ev.xclient.data.l[0] = timestamp;
578 ev.xclient.data.l[1] = scr->managerAtom;
579 ev.xclient.data.l[2] = scr->managerWindow;
580 ev.xclient.data.l[3] = 0;
581 ev.xclient.data.l[4] = 0;
583 XSendEvent(dpy, scr->root_win, False, StructureNotify, &ev);
584 XSync(dpy, False);
586 return True;
588 #endif
591 *----------------------------------------------------------------------
592 * wScreenInit--
593 * Initializes the window manager for the given screen and
594 * allocates a WScreen descriptor for it. Many resources are allocated
595 * for the screen and the root window is setup appropriately.
597 * Returns:
598 * The WScreen descriptor for the screen.
600 * Side effects:
601 * Many resources are allocated and the IconSize property is
602 * set on the root window.
603 * The program can be aborted if some fatal error occurs.
605 * TODO: User specifiable visual.
606 *----------------------------------------------------------------------
608 WScreen*
609 wScreenInit(int screen_number)
611 WScreen *scr;
612 XIconSize icon_size[1];
613 RContextAttributes rattr;
614 extern int wVisualID;
615 long event_mask;
616 WMColor *color;
617 XErrorHandler oldHandler;
619 scr = wmalloc(sizeof(WScreen));
620 memset(scr, 0, sizeof(WScreen));
622 scr->stacking_list = WMCreateTreeBag();
624 /* initialize globals */
625 scr->screen = screen_number;
626 scr->root_win = RootWindow(dpy, screen_number);
627 scr->depth = DefaultDepth(dpy, screen_number);
628 scr->colormap = DefaultColormap(dpy, screen_number);
630 scr->scr_width = WidthOfScreen(ScreenOfDisplay(dpy, screen_number));
631 scr->scr_height = HeightOfScreen(ScreenOfDisplay(dpy, screen_number));
633 scr->usableArea.x2 = scr->scr_width;
634 scr->usableArea.y2 = scr->scr_height;
635 scr->totalUsableArea.x2 = scr->scr_width;
636 scr->totalUsableArea.y2 = scr->scr_height;
638 scr->fakeGroupLeaders = WMCreateArray(16);
640 #if 0
641 if (!aquireManagerSelection(scr)) {
642 wfree(scr);
644 return NULL;
646 #endif
647 CantManageScreen = 0;
648 oldHandler = XSetErrorHandler((XErrorHandler)alreadyRunningError);
650 event_mask = EVENT_MASK;
652 if (wPreferences.disable_root_mouse) {
653 event_mask &= ~(ButtonPressMask|ButtonReleaseMask);
656 XSelectInput(dpy, scr->root_win, event_mask);
658 #ifdef KEEP_XKB_LOCK_STATUS
659 /* Only GroupLock doesn't work correctly in my system since right-alt
660 * can change mode while holding it too - ]d
662 if (wXkbSupported) {
663 XkbSelectEvents(dpy,XkbUseCoreKbd,
664 XkbStateNotifyMask,
665 XkbStateNotifyMask);
667 #endif /* KEEP_XKB_LOCK_STATUS */
669 XSync(dpy, False);
670 XSetErrorHandler(oldHandler);
672 if (CantManageScreen) {
673 wfree(scr);
674 return NULL;
677 #ifdef XINERAMA
678 wInitXinerama(scr);
679 #endif
682 XDefineCursor(dpy, scr->root_win, wCursor[WCUR_ROOT]);
684 /* screen descriptor for raster graphic library */
685 rattr.flags = RC_RenderMode | RC_ColorsPerChannel | RC_StandardColormap;
686 rattr.render_mode = wPreferences.no_dithering
687 ? RBestMatchRendering
688 : RDitheredRendering;
690 /* if the std colormap stuff works ok, this will be ignored */
691 rattr.colors_per_channel = wPreferences.cmap_size;
692 if (rattr.colors_per_channel<2)
693 rattr.colors_per_channel = 2;
696 /* will only be accounted for in PseudoColor */
697 if (wPreferences.flags.create_stdcmap) {
698 rattr.standard_colormap_mode = RCreateStdColormap;
699 } else {
700 rattr.standard_colormap_mode = RUseStdColormap;
703 if (wVisualID>=0) {
704 rattr.flags |= RC_VisualID;
705 rattr.visualid = wVisualID;
708 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
710 if (!scr->rcontext && RErrorCode == RERR_STDCMAPFAIL) {
711 wwarning(RMessageForError(RErrorCode));
713 rattr.flags &= ~RC_StandardColormap;
714 rattr.standard_colormap_mode = RUseStdColormap;
716 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
719 if (!scr->rcontext) {
720 wwarning(_("could not initialize graphics library context: %s"),
721 RMessageForError(RErrorCode));
722 wAbort(False);
723 } else {
724 char **formats;
725 int i = 0;
727 formats = RSupportedFileFormats();
728 if (formats) {
729 for (i=0; formats[i]!=NULL; i++) {
730 if (strcmp(formats[i], "TIFF")==0) {
731 scr->flags.supports_tiff = 1;
732 break;
738 scr->w_win = scr->rcontext->drawable;
739 scr->w_visual = scr->rcontext->visual;
740 scr->w_depth = scr->rcontext->depth;
741 scr->w_colormap = scr->rcontext->cmap;
743 /* create screen descriptor for WINGs */
744 scr->wmscreen = WMCreateScreenWithRContext(dpy, screen_number,
745 scr->rcontext);
747 if (!scr->wmscreen) {
748 wfatal(_("could not initialize WINGs widget set"));
749 return NULL;
752 scr->black = WMBlackColor(scr->wmscreen);
753 scr->white = WMWhiteColor(scr->wmscreen);
754 scr->gray = WMGrayColor(scr->wmscreen);
755 scr->darkGray = WMDarkGrayColor(scr->wmscreen);
757 scr->black_pixel = WMColorPixel(scr->black); /*scr->rcontext->black;*/
758 scr->white_pixel = WMColorPixel(scr->white); /*scr->rcontext->white;*/
759 scr->light_pixel = WMColorPixel(scr->gray);
760 scr->dark_pixel = WMColorPixel(scr->darkGray);
763 XColor xcol;
764 /* frame boder color */
765 wGetColor(scr, FRAME_BORDER_COLOR, &xcol);
766 scr->frame_border_pixel = xcol.pixel;
769 /* create GCs with default values */
770 allocGCs(scr);
772 /* for our window manager info notice board. Need to
773 * create before reading the defaults, because it will be used there.
775 scr->info_window = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 10, 10,
776 0, 0, 0);
778 /* read defaults for this screen */
779 wReadDefaults(scr, WDWindowMaker->dictionary);
781 createInternalWindows(scr);
783 #ifdef KWM_HINTS
784 wKWMInitStuff(scr);
785 #endif
787 #ifdef GNOME_STUFF
788 wGNOMEInitStuff(scr);
789 #endif
791 #ifdef OLWM_HINTS
792 wOLWMInitStuff(scr);
793 #endif
795 /* create initial workspace */
796 wWorkspaceNew(scr);
798 /* create shared pixmaps */
799 createPixmaps(scr);
801 /* set icon sizes we can accept from clients */
802 icon_size[0].min_width = 8;
803 icon_size[0].min_height = 8;
804 icon_size[0].max_width = wPreferences.icon_size-4;
805 icon_size[0].max_height = wPreferences.icon_size-4;
806 icon_size[0].width_inc = 1;
807 icon_size[0].height_inc = 1;
808 XSetIconSizes(dpy, scr->root_win, icon_size, 1);
810 /* setup WindowMaker protocols property in the root window*/
811 PropSetWMakerProtocols(scr->root_win);
813 /* setup our noticeboard */
814 XChangeProperty(dpy, scr->info_window, _XA_WINDOWMAKER_NOTICEBOARD,
815 XA_WINDOW, 32, PropModeReplace,
816 (unsigned char*)&scr->info_window, 1);
817 XChangeProperty(dpy, scr->root_win, _XA_WINDOWMAKER_NOTICEBOARD,
818 XA_WINDOW, 32, PropModeReplace,
819 (unsigned char*)&scr->info_window, 1);
822 #ifdef BALLOON_TEXT
823 /* initialize balloon text stuff */
824 wBalloonInitialize(scr);
825 #endif
827 scr->info_text_font = WMBoldSystemFontOfSize(scr->wmscreen, 12);
830 scr->gview = WCreateGeometryView(scr->wmscreen);
831 WMRealizeWidget(scr->gview);
833 wScreenUpdateUsableArea(scr);
835 return scr;
840 static WArea subtractRectangle(WArea area, WArea rect)
842 WArea result = area;
848 void
849 wScreenUpdateUsableArea(WScreen *scr)
851 WReservedArea *area;
853 scr->totalUsableArea = scr->usableArea;
856 if (scr->dock && (!scr->dock->lowered
857 || wPreferences.no_window_over_dock)) {
859 int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
861 if (scr->dock->on_right_side) {
862 scr->totalUsableArea.x2 = WMIN(scr->totalUsableArea.x2,
863 scr->scr_width - offset);
864 } else {
865 scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, offset);
869 if (wPreferences.no_window_over_icons) {
870 if (wPreferences.icon_yard & IY_VERT) {
872 if (!(wPreferences.icon_yard & IY_RIGHT)) {
873 scr->totalUsableArea.x1 += wPreferences.icon_size;
874 } else {
875 scr->totalUsableArea.x2 -= wPreferences.icon_size;
877 } else {
879 if (wPreferences.icon_yard & IY_TOP) {
880 scr->totalUsableArea.y1 += wPreferences.icon_size;
881 } else {
882 scr->totalUsableArea.y2 -= wPreferences.icon_size;
887 #ifdef KWM_HINTS
889 WArea area;
891 if (wKWMGetUsableArea(scr, &area)) {
892 scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, area.x1);
893 scr->totalUsableArea.y1 = WMAX(scr->totalUsableArea.y1, area.y1);
894 scr->totalUsableArea.x2 = WMIN(scr->totalUsableArea.x2, area.x2);
895 scr->totalUsableArea.y2 = WMIN(scr->totalUsableArea.y2, area.y2);
898 #endif
900 #ifdef GNOME_STUFF
901 area = scr->reservedAreas;
903 while (area) {
904 int th, bh;
905 int lw, rw;
906 int w, h;
908 w = area->area.x2 - area->area.x1;
909 h = area->area.y2 - area->area.y1;
911 th = area->area.y1;
912 bh = scr->scr_height - area->area.y2;
913 lw = area->area.x1;
914 rw = scr->scr_width - area->area.x2;
916 if (WMIN(th, bh) <= WMIN(lw, rw)) {
917 /* horizontal */
918 if (th < bh) {
919 /* on top */
920 if (scr->totalUsableArea.y1 < area->area.y2)
921 scr->totalUsableArea.y1 = area->area.y2;
922 } else {
923 /* on bottom */
924 if (scr->totalUsableArea.y2 > area->area.y1)
925 scr->totalUsableArea.y2 = area->area.y1;
927 } else {
928 /* vertical */
929 if (lw < rw) {
930 /* on left */
931 if (scr->totalUsableArea.x1 < area->area.x2)
932 scr->totalUsableArea.x1 = area->area.x2;
933 } else {
934 /* on right */
935 if (scr->totalUsableArea.x2 > area->area.x1)
936 scr->totalUsableArea.x2 = area->area.x1;
940 area = area->next;
942 #endif /* GNOME_STUFF */
944 if (scr->totalUsableArea.x2 - scr->totalUsableArea.x1 < scr->scr_width/2) {
945 scr->totalUsableArea.x2 = scr->usableArea.x2;
946 scr->totalUsableArea.x1 = scr->usableArea.x1;
948 if (scr->totalUsableArea.y2 - scr->totalUsableArea.y1 < scr->scr_height/2) {
949 scr->totalUsableArea.y2 = scr->usableArea.y2;
950 scr->totalUsableArea.y1 = scr->usableArea.y1;
953 #ifdef not_used
954 #ifdef KWM_HINTS
956 int i;
958 for (i = 0; i < scr->workspace_count; i++) {
959 wKWMSetUsableAreaHint(scr, i);
962 #endif
963 #endif
966 unsigned size = wPreferences.workspace_border_size;
967 unsigned position = wPreferences.workspace_border_position;
969 if (size>0 && position!=WB_NONE) {
970 if (position & WB_LEFTRIGHT) {
971 scr->totalUsableArea.x1 += size;
972 scr->totalUsableArea.x2 -= size;
974 if (position & WB_TOPBOTTOM) {
975 scr->totalUsableArea.y1 += size;
976 scr->totalUsableArea.y2 -= size;
984 void
985 wScreenRestoreState(WScreen *scr)
987 WMPropList *state;
988 char *path;
991 #ifndef LITE
992 OpenRootMenu(scr, -10000, -10000, False);
993 wMenuUnmap(scr->root_menu);
994 #endif
996 make_keys();
998 if (wScreenCount == 1) {
999 path = wdefaultspathfordomain("WMState");
1000 } else {
1001 char buf[16];
1002 snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
1003 path = wdefaultspathfordomain(buf);
1005 scr->session_state = WMReadPropListFromFile(path);
1006 wfree(path);
1007 if (!scr->session_state && wScreenCount>1) {
1008 path = wdefaultspathfordomain("WMState");
1009 scr->session_state = WMReadPropListFromFile(path);
1010 wfree(path);
1013 if (!wPreferences.flags.noclip && scr->session_state) {
1014 state = WMGetFromPLDictionary(scr->session_state, dClip);
1015 scr->clip_icon = wClipRestoreState(scr, state);
1018 wWorkspaceRestoreState(scr);
1020 #ifdef VIRTUAL_DESKTOP
1022 * * create inputonly windows at the border of screen
1023 * */
1024 wWorkspaceManageEdge(scr);
1025 #endif
1027 if (!wPreferences.flags.nodock && scr->session_state) {
1028 state = WMGetFromPLDictionary(scr->session_state, dDock);
1029 scr->dock = wDockRestoreState(scr, state, WM_DOCK);
1032 wScreenUpdateUsableArea(scr);
1036 void
1037 wScreenSaveState(WScreen *scr)
1039 WWindow *wwin;
1040 char *str;
1041 WMPropList *old_state, *foo;
1042 CARD32 data[2];
1045 make_keys();
1047 /* Save current workspace, so can go back to it upon restart. */
1048 data[0] = scr->current_workspace;
1049 data[1] = WFLAGS_NONE;
1051 XChangeProperty(dpy, scr->root_win, _XA_WINDOWMAKER_STATE,
1052 _XA_WINDOWMAKER_STATE, 32, PropModeReplace,
1053 (unsigned char *) data, 2);
1055 /* save state of windows */
1056 wwin = scr->focused_window;
1057 while (wwin) {
1058 wWindowSaveState(wwin);
1059 wwin = wwin->prev;
1063 if (wPreferences.flags.noupdates)
1064 return;
1067 old_state = scr->session_state;
1068 scr->session_state = WMCreatePLDictionary(NULL, NULL, NULL);
1070 WMPLSetCaseSensitive(True);
1072 /* save dock state to file */
1073 if (!wPreferences.flags.nodock) {
1074 wDockSaveState(scr, old_state);
1075 } else {
1076 if ((foo = WMGetFromPLDictionary(old_state, dDock))!=NULL) {
1077 WMPutInPLDictionary(scr->session_state, dDock, foo);
1080 if (!wPreferences.flags.noclip) {
1081 wClipSaveState(scr);
1082 } else {
1083 if ((foo = WMGetFromPLDictionary(old_state, dClip))!=NULL) {
1084 WMPutInPLDictionary(scr->session_state, dClip, foo);
1088 wWorkspaceSaveState(scr, old_state);
1090 if (wPreferences.save_session_on_exit) {
1091 wSessionSaveState(scr);
1092 } else {
1093 if ((foo = WMGetFromPLDictionary(old_state, dApplications))!=NULL) {
1094 WMPutInPLDictionary(scr->session_state, dApplications, foo);
1096 if ((foo = WMGetFromPLDictionary(old_state, dWorkspace))!=NULL) {
1097 WMPutInPLDictionary(scr->session_state, dWorkspace, foo);
1101 /* clean up */
1102 WMPLSetCaseSensitive(False);
1104 wMenuSaveState(scr);
1106 if (wScreenCount == 1)
1107 str = wdefaultspathfordomain("WMState");
1108 else {
1109 char buf[16];
1110 snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
1111 str = wdefaultspathfordomain(buf);
1113 if (!WMWritePropListToFile(scr->session_state, str, True)) {
1114 wsyserror(_("could not save session state in %s"), str);
1116 wfree(str);
1117 WMReleasePropList(old_state);
1123 wScreenBringInside(WScreen *scr, int *x, int *y, int width, int height)
1125 int moved = 0;
1126 int tol_w, tol_h;
1128 if (width > 20)
1129 tol_w = width/2;
1130 else
1131 tol_w = 20;
1133 if (height > 20)
1134 tol_h = height/2;
1135 else
1136 tol_h = 20;
1138 if (*x+width < 10)
1139 *x = -tol_w, moved = 1;
1140 else if (*x >= scr->scr_width - 10)
1141 *x = scr->scr_width - tol_w - 1, moved = 1;
1143 if (*y < -height + 10)
1144 *y = -tol_h, moved = 1;
1145 else if (*y >= scr->scr_height - 10)
1146 *y = scr->scr_height - tol_h - 1, moved = 1;
1148 return moved;