kde 1.1 update
[wmaker-crm.git] / src / screen.c
blobf1b01a3ce8b1c16ae0c1696c4cef5adae1610ffc
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 #ifndef NEWSTUFF
159 static void
160 allocButtonPixmaps(WScreen *scr)
162 WPixmap *pix;
164 /* create predefined pixmaps */
165 pix = wPixmapCreateFromXPMData(scr, PRED_CLOSE_XPM);
166 if (pix)
167 pix->shared = 1;
168 scr->b_pixmaps[WBUT_CLOSE] = pix;
170 pix = wPixmapCreateFromXPMData(scr, PRED_BROKEN_CLOSE_XPM);
171 if (pix)
172 pix->shared = 1;
173 scr->b_pixmaps[WBUT_BROKENCLOSE] = pix;
175 pix = wPixmapCreateFromXPMData(scr, PRED_ICONIFY_XPM);
176 if (pix)
177 pix->shared = 1;
178 scr->b_pixmaps[WBUT_ICONIFY] = pix;
180 pix = wPixmapCreateFromXPMData(scr, PRED_KILL_XPM);
181 if (pix)
182 pix->shared = 1;
183 scr->b_pixmaps[WBUT_KILL] = pix;
185 #endif
189 static void
190 draw_dot(WScreen *scr, Drawable d, int x, int y, GC gc)
192 XSetForeground(dpy, gc, scr->black_pixel);
193 XDrawLine(dpy, d, gc, x, y, x+1, y);
194 XDrawPoint(dpy, d, gc, x, y+1);
195 XSetForeground(dpy, gc, scr->white_pixel);
196 XDrawLine(dpy, d, gc, x+2, y, x+2, y+1);
197 XDrawPoint(dpy, d, gc, x+1, y+1);
201 static WPixmap*
202 make3Dots(WScreen *scr)
204 WPixmap *wpix;
205 GC gc2, gc;
206 XGCValues gcv;
207 Pixmap pix, mask;
209 gc = scr->copy_gc;
210 pix = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size,
211 wPreferences.icon_size, scr->w_depth);
212 XSetForeground(dpy, gc, scr->black_pixel);
213 XFillRectangle(dpy, pix, gc, 0, 0, wPreferences.icon_size,
214 wPreferences.icon_size);
215 XSetForeground(dpy, gc, scr->white_pixel);
216 draw_dot(scr, pix, 4, wPreferences.icon_size-6, gc);
217 draw_dot(scr, pix, 9, wPreferences.icon_size-6, gc);
218 draw_dot(scr, pix, 14, wPreferences.icon_size-6, gc);
220 mask = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size,
221 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,
226 wPreferences.icon_size);
227 XSetForeground(dpy, gc2, 1);
228 XFillRectangle(dpy, mask, gc2, 4, wPreferences.icon_size-6, 3, 2);
229 XFillRectangle(dpy, mask, gc2, 9, wPreferences.icon_size-6, 3, 2);
230 XFillRectangle(dpy, mask, gc2, 14, wPreferences.icon_size-6, 3, 2);
232 XFreeGC(dpy, gc2);
234 wpix = wPixmapCreate(scr, pix, mask);
235 wpix->shared = 1;
237 return wpix;
241 static void
242 allocGCs(WScreen *scr)
244 XGCValues gcv;
245 XColor color;
246 unsigned long mtextcolor;
247 int gcm;
249 scr->stipple_bitmap =
250 XCreateBitmapFromData(dpy, scr->w_win, STIPPLE_DATA, STIPPLE_WIDTH,
251 STIPPLE_HEIGHT);
253 gcv.stipple = scr->stipple_bitmap;
254 gcv.foreground = scr->white_pixel;
255 gcv.fill_style = FillStippled;
256 gcv.graphics_exposures = False;
257 gcm = GCForeground|GCStipple|GCFillStyle|GCGraphicsExposures;
258 scr->stipple_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
261 /* selected icon border GCs */
262 gcv.function = GXcopy;
263 gcv.foreground = scr->white_pixel;
264 gcv.background = scr->black_pixel;
265 gcv.line_width = 1;
266 gcv.line_style = LineDoubleDash;
267 gcv.fill_style = FillSolid;
268 gcv.dash_offset = 0;
269 gcv.dashes = 4;
270 gcv.graphics_exposures = False;
272 gcm = GCFunction | GCGraphicsExposures;
273 gcm |= GCForeground | GCBackground;
274 gcm |= GCLineWidth | GCLineStyle;
275 gcm |= GCFillStyle;
276 gcm |= GCDashOffset | GCDashList;
278 scr->icon_select_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
280 gcm = GCForeground|GCGraphicsExposures;
282 scr->menu_title_pixel[0] = scr->white_pixel;
283 gcv.foreground = scr->white_pixel;
284 gcv.graphics_exposures = False;
285 scr->menu_title_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
287 scr->mtext_pixel = scr->black_pixel;
288 mtextcolor = gcv.foreground = scr->black_pixel;
289 scr->menu_entry_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
291 /* selected menu entry GC */
292 gcm = GCForeground|GCBackground|GCGraphicsExposures;
293 gcv.foreground = scr->white_pixel;
294 gcv.background = scr->white_pixel;
295 gcv.graphics_exposures = False;
296 scr->select_menu_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
298 /* disabled menu entry GC */
299 scr->dtext_pixel = scr->black_pixel;
300 gcm = GCForeground|GCBackground|GCStipple|GCGraphicsExposures;
301 gcv.stipple = scr->stipple_bitmap;
302 gcv.graphics_exposures = False;
303 scr->disabled_menu_entry_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
305 /* frame GC */
306 wGetColor(scr, DEF_FRAME_COLOR, &color);
307 gcv.function = GXxor;
308 /* this will raise the probability of the XORed color being different
309 * of the original color in PseudoColor when not all color cells are
310 * initialized */
311 if (DefaultVisual(dpy, scr->screen)->class==PseudoColor)
312 gcv.plane_mask = (1<<(scr->depth-1))|1;
313 else
314 gcv.plane_mask = AllPlanes;
315 gcv.foreground = color.pixel;
316 if (gcv.foreground == 0)
317 gcv.foreground = 1;
318 gcv.line_width = DEF_FRAME_THICKNESS;
319 gcv.subwindow_mode = IncludeInferiors;
320 gcv.graphics_exposures = False;
321 scr->frame_gc = XCreateGC(dpy, scr->root_win, GCForeground|GCGraphicsExposures
322 |GCFunction|GCSubwindowMode|GCLineWidth
323 |GCPlaneMask, &gcv);
325 /* line GC */
326 gcv.foreground = color.pixel;
328 if (gcv.foreground == 0)
329 /* XOR:ing with a zero is not going to be of much use, so
330 in that case, we somewhat arbitrarily xor with 17 instead. */
331 gcv.foreground = 17;
333 gcv.function = GXxor;
334 gcv.subwindow_mode = IncludeInferiors;
335 gcv.line_width = 1;
336 gcv.cap_style = CapRound;
337 gcv.graphics_exposures = False;
338 gcm = GCForeground|GCFunction|GCSubwindowMode|GCLineWidth|GCCapStyle
339 |GCGraphicsExposures;
340 scr->line_gc = XCreateGC(dpy, scr->root_win, gcm, &gcv);
342 scr->line_pixel = gcv.foreground;
344 /* copy GC */
345 gcv.foreground = scr->white_pixel;
346 gcv.background = scr->black_pixel;
347 gcv.graphics_exposures = False;
348 scr->copy_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
349 |GCGraphicsExposures, &gcv);
351 /* window title text GC */
352 gcv.graphics_exposures = False;
353 scr->window_title_gc = XCreateGC(dpy, scr->w_win,GCGraphicsExposures,&gcv);
355 /* icon title GC */
356 scr->icon_title_gc = XCreateGC(dpy, scr->w_win, GCGraphicsExposures, &gcv);
358 /* clip title GC */
359 scr->clip_title_gc = XCreateGC(dpy, scr->w_win, GCGraphicsExposures, &gcv);
361 /* move/size display GC */
362 gcv.graphics_exposures = False;
363 gcm = GCGraphicsExposures;
364 scr->info_text_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
366 /* misc drawing GC */
367 gcv.graphics_exposures = False;
368 gcm = GCGraphicsExposures;
369 scr->draw_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
374 static void
375 createPixmaps(WScreen *scr)
377 WPixmap *pix;
378 WMPixmap *wmpix;
379 RImage *image;
380 Pixmap p, m;
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 if (!RConvertImageMask(scr->rcontext, image, &p, &m, 128)) {
437 wwarning(_("error making logo image for panel:%s"), RMessageForError(RErrorCode));
438 } else {
439 wmpix = WMCreatePixmapFromXPixmaps(scr->wmscreen, p, m,
440 image->width, image->height,
441 scr->depth);
442 WMSetApplicationIconImage(scr->wmscreen, wmpix);
443 WMReleasePixmap(wmpix);
445 RDestroyImage(image);
448 if (!wPreferences.flags.nodock || !wPreferences.flags.noclip) {
449 scr->dock_dots = make3Dots(scr);
452 #ifndef NEWSTUFF
453 /* titlebar button pixmaps */
454 allocButtonPixmaps(scr);
455 #endif
460 *----------------------------------------------------------------------
461 * createInternalWindows--
462 * Creates some windows used internally by the program. One to
463 * receive input focus when no other window can get it and another
464 * to display window geometry information during window resize/move.
466 * Returns:
467 * Nothing
469 * Side effects:
470 * Windows are created and some colors are allocated for the
471 * window background.
472 *----------------------------------------------------------------------
474 static void
475 createInternalWindows(WScreen *scr)
477 int vmask;
478 XSetWindowAttributes attribs;
480 /* window for displaying geometry information during resizes and moves */
481 vmask = CWBorderPixel|CWBackPixmap|CWBackPixel|CWCursor|CWSaveUnder|CWOverrideRedirect;
482 attribs.border_pixel = 0;
483 attribs.save_under = True;
484 attribs.override_redirect = True;
485 attribs.cursor = wCursor[WCUR_DEFAULT];
486 attribs.background_pixmap = None;
487 if (scr->resizebar_texture[0])
488 attribs.background_pixel = scr->resizebar_texture[0]->normal.pixel;
489 else
490 attribs.background_pixel = scr->light_pixel;
491 vmask |= CWColormap;
492 attribs.colormap = scr->w_colormap;
494 wGetGeometryWindowSize(scr, &scr->geometry_display_width,
495 &scr->geometry_display_height);
496 scr->geometry_display =
497 XCreateWindow(dpy, scr->root_win, 1, 1,
498 scr->geometry_display_width,
499 scr->geometry_display_height,
500 1, scr->w_depth, CopyFromParent, scr->w_visual,
501 vmask, &attribs);
503 /* InputOnly window to get the focus when no other window can get it */
504 vmask = CWEventMask|CWOverrideRedirect;
505 attribs.event_mask = KeyPressMask|FocusChangeMask;
506 attribs.override_redirect = True;
507 scr->no_focus_win=XCreateWindow(dpy,scr->root_win,-10, -10, 4, 4, 0, 0,
508 InputOnly,CopyFromParent, vmask, &attribs);
509 XSelectInput(dpy, scr->no_focus_win, KeyPressMask|KeyReleaseMask);
510 XMapWindow(dpy, scr->no_focus_win);
512 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
514 /* shadow window for dock buttons */
515 vmask = CWBorderPixel|CWBackPixmap|CWBackPixel|CWCursor|CWSaveUnder|CWOverrideRedirect;
516 attribs.border_pixel = 0;
517 attribs.save_under = True;
518 attribs.override_redirect = True;
519 attribs.background_pixmap = None;
520 attribs.background_pixel = scr->white_pixel;
521 vmask |= CWColormap;
522 attribs.colormap = scr->w_colormap;
523 scr->dock_shadow =
524 XCreateWindow(dpy, scr->root_win, 0, 0, wPreferences.icon_size,
525 wPreferences.icon_size, 0, scr->w_depth, CopyFromParent,
526 scr->w_visual, vmask, &attribs);
528 /* workspace name balloon for clip */
529 vmask = CWBackPixel|CWSaveUnder|CWOverrideRedirect|CWColormap
530 |CWBorderPixel;
531 attribs.save_under = True;
532 attribs.override_redirect = True;
533 attribs.colormap = scr->w_colormap;
534 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
535 attribs.border_pixel = 0; /* do not care */
536 scr->clip_balloon =
537 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
538 CopyFromParent, scr->w_visual, vmask, &attribs);
541 /* for our window manager info notice board */
542 scr->info_window =
543 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, CopyFromParent,
544 CopyFromParent, CopyFromParent, CWOverrideRedirect,
545 &attribs);
548 * If the window is clicked without having ButtonPress selected, the
549 * resulting event will have event.xbutton.window == root.
551 XSelectInput(dpy, scr->clip_balloon, ButtonPressMask);
555 #if 0
556 static Bool
557 aquireManagerSelection(WScreen *scr)
559 char buffer[32];
560 XEvent ev;
561 Time timestamp;
563 sprintf(buffer, "WM_S%i", scr->screen);
564 scr->managerAtom = XInternAtom(dpy, buffer, False);
566 /* for race-conditions... */
567 XGrabServer(dpy);
569 /* if there is another manager running, don't try to replace it
570 * (for now, at least) */
571 if (XGetSelectionOwner(dpy, scr->managerAtom) != None) {
572 XUngrabServer(dpy);
573 return False;
576 /* become the manager for this screen */
578 scr->managerWindow = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 1, 1,
579 0, 0, 0);
581 XSelectInput(dpy, scr->managerWindow, PropertyChangeMask);
582 /* get a timestamp */
583 XChangeProperty(dpy, scr->managerWindow, scr->managerAtom,
584 XA_INTEGER, 32, PropModeAppend, NULL, 0);
585 while (1) {
586 XWindowEvent(dpy, scr->managerWindow, &ev);
587 if (ev.type == PropertyNotify) {
588 timestamp = ev.xproperty.time;
589 break;
592 XSelectInput(dpy, scr->managerWindow, NoEvents);
593 XDeleteProperty(dpy, scr->managerWindow, scr->managerAtom);
595 XSetSelectionOwner(dpy, scr->managerAtom, scr->managerWindow, CurrentTime);
597 XUngrabServer(dpy);
599 /* announce our arrival */
601 ev.xclient.type = ClientMessage;
602 ev.xclient.message_type = XInternAtom(dpy, "MANAGER", False);
603 ev.xclient.destination = scr->root_win;
604 ev.xclient.format = 32;
605 ev.xclient.data.l[0] = timestamp;
606 ev.xclient.data.l[1] = scr->managerAtom;
607 ev.xclient.data.l[2] = scr->managerWindow;
608 ev.xclient.data.l[3] = 0;
609 ev.xclient.data.l[4] = 0;
611 XSendEvent(dpy, scr->root_win, False, StructureNotify, &ev);
612 XSync(dpy, False);
614 return True;
616 #endif
619 *----------------------------------------------------------------------
620 * wScreenInit--
621 * Initializes the window manager for the given screen and
622 * allocates a WScreen descriptor for it. Many resources are allocated
623 * for the screen and the root window is setup appropriately.
625 * Returns:
626 * The WScreen descriptor for the screen.
628 * Side effects:
629 * Many resources are allocated and the IconSize property is
630 * set on the root window.
631 * The program can be aborted if some fatal error occurs.
633 * TODO: User specifiable visual.
634 *----------------------------------------------------------------------
636 WScreen*
637 wScreenInit(int screen_number)
639 WScreen *scr;
640 XIconSize icon_size[1];
641 RContextAttributes rattr;
642 extern int wVisualID;
643 long event_mask;
644 WMColor *color;
645 XErrorHandler oldHandler;
647 scr = wmalloc(sizeof(WScreen));
648 memset(scr, 0, sizeof(WScreen));
650 /* initialize globals */
651 scr->screen = screen_number;
652 scr->root_win = RootWindow(dpy, screen_number);
653 scr->depth = DefaultDepth(dpy, screen_number);
654 scr->colormap = DefaultColormap(dpy, screen_number);
656 scr->scr_width = WidthOfScreen(ScreenOfDisplay(dpy, screen_number));
657 scr->scr_height = HeightOfScreen(ScreenOfDisplay(dpy, screen_number));
659 scr->usableArea.x2 = scr->scr_width;
660 scr->usableArea.y2 = scr->scr_height;
661 scr->totalUsableArea.x2 = scr->scr_width;
662 scr->totalUsableArea.y2 = scr->scr_height;
664 #if 0
665 if (!aquireManagerSelection(scr)) {
666 free(scr);
668 return NULL;
670 #endif
671 CantManageScreen = 0;
672 oldHandler = XSetErrorHandler((XErrorHandler)alreadyRunningError);
674 event_mask = EVENT_MASK;
676 if (wPreferences.disable_root_mouse) {
677 event_mask &= ~(ButtonPressMask|ButtonReleaseMask);
680 XSelectInput(dpy, scr->root_win, event_mask);
682 #ifdef KEEP_XKB_LOCK_STATUS
683 XkbSelectEvents(dpy,XkbUseCoreKbd,XkbIndicatorStateNotifyMask,
684 XkbIndicatorStateNotifyMask);
685 #endif /* KEEP_XKB_LOCK_STATUS */
687 XSync(dpy, False);
688 XSetErrorHandler(oldHandler);
690 if (CantManageScreen) {
691 free(scr);
692 return NULL;
695 XDefineCursor(dpy, scr->root_win, wCursor[WCUR_DEFAULT]);
697 /* screen descriptor for raster graphic library */
698 rattr.flags = RC_RenderMode | RC_ColorsPerChannel;
699 rattr.render_mode = wPreferences.no_dithering?RM_MATCH:RM_DITHER;
700 rattr.colors_per_channel = wPreferences.cmap_size;
701 if (rattr.colors_per_channel<2)
702 rattr.colors_per_channel = 2;
704 if (wVisualID>=0) {
705 rattr.flags |= RC_VisualID;
706 rattr.visualid = wVisualID;
708 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
709 if (!scr->rcontext) {
710 wwarning(_("could not initialize graphics library context: %s"),
711 RMessageForError(RErrorCode));
712 wAbort(False);
713 } else {
714 char **formats;
715 int i = 0;
717 formats = RSupportedFileFormats();
718 if (formats) {
719 for (i=0; formats[i]!=NULL; i++) {
720 if (strcmp(formats[i], "TIFF")==0) {
721 scr->flags.supports_tiff = 1;
722 break;
728 scr->w_win = scr->rcontext->drawable;
729 scr->w_visual = scr->rcontext->visual;
730 scr->w_depth = scr->rcontext->depth;
731 scr->w_colormap = scr->rcontext->cmap;
733 scr->black_pixel = scr->rcontext->black;
734 scr->white_pixel = scr->rcontext->white;
736 /* create screen descriptor for WINGs */
737 scr->wmscreen = WMCreateScreenWithRContext(dpy, screen_number,
738 scr->rcontext);
740 if (!scr->wmscreen) {
741 wfatal(_("could not do initialization of WINGs widget set"));
743 return NULL;
746 color = WMGrayColor(scr->wmscreen);
747 scr->light_pixel = WMColorPixel(color);
748 WMReleaseColor(color);
750 color = WMDarkGrayColor(scr->wmscreen);
751 scr->dark_pixel = WMColorPixel(color);
752 WMReleaseColor(color);
755 XColor xcol;
756 /* frame boder color */
757 wGetColor(scr, FRAME_BORDER_COLOR, &xcol);
758 scr->frame_border_pixel = xcol.pixel;
761 /* create GCs with default values */
762 allocGCs(scr);
764 /* read defaults for this screen */
765 wReadDefaults(scr, WDWindowMaker->dictionary);
767 createInternalWindows(scr);
769 #ifdef KWM_HINTS
770 wKWMInitStuff(scr);
771 #endif
773 #ifdef GNOME_STUFF
774 wGNOMEInitStuff(scr);
775 #endif
777 #ifdef OLWM_HINTS
778 wOLWMInitStuff(scr);
779 #endif
781 /* create initial workspace */
782 wWorkspaceNew(scr);
784 /* create shared pixmaps */
785 createPixmaps(scr);
787 /* set icon sizes we can accept from clients */
788 icon_size[0].min_width = 8;
789 icon_size[0].min_height = 8;
790 icon_size[0].max_width = wPreferences.icon_size-4;
791 icon_size[0].max_height = wPreferences.icon_size-4;
792 icon_size[0].width_inc = 1;
793 icon_size[0].height_inc = 1;
794 XSetIconSizes(dpy, scr->root_win, icon_size, 1);
796 /* setup WindowMaker protocols property in the root window*/
797 PropSetWMakerProtocols(scr->root_win);
799 /* setup our noticeboard */
800 XChangeProperty(dpy, scr->info_window, _XA_WINDOWMAKER_NOTICEBOARD,
801 XA_WINDOW, 32, PropModeReplace,
802 (unsigned char*)&scr->info_window, 1);
803 XChangeProperty(dpy, scr->root_win, _XA_WINDOWMAKER_NOTICEBOARD,
804 XA_WINDOW, 32, PropModeReplace,
805 (unsigned char*)&scr->info_window, 1);
808 #ifdef BALLOON_TEXT
809 /* initialize balloon text stuff */
810 wBalloonInitialize(scr);
811 #endif
813 wScreenUpdateUsableArea(scr);
815 #ifndef LITE
816 /* kluge to load menu configurations at startup */
817 OpenRootMenu(scr, -10000, -10000, False);
818 wMenuUnmap(scr->root_menu);
819 #endif
821 return scr;
825 void
826 wScreenUpdateUsableArea(WScreen *scr)
828 #ifdef GNOME_STUFF
829 WReservedArea *area;
830 #endif
832 scr->totalUsableArea = scr->usableArea;
835 if (scr->dock && (!scr->dock->lowered
836 || wPreferences.no_window_over_dock)) {
838 int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
840 if (scr->dock->on_right_side) {
841 scr->totalUsableArea.x2 = WMIN(scr->totalUsableArea.x2,
842 scr->scr_width - offset);
843 } else {
844 scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, offset);
848 if (wPreferences.no_window_over_icons) {
849 if (wPreferences.icon_yard & IY_VERT) {
851 if (!(wPreferences.icon_yard & IY_RIGHT)) {
852 scr->totalUsableArea.x1 += wPreferences.icon_size;
853 } else {
854 scr->totalUsableArea.x2 -= wPreferences.icon_size;
856 } else {
858 if (wPreferences.icon_yard & IY_TOP) {
859 scr->totalUsableArea.y1 += wPreferences.icon_size;
860 } else {
861 scr->totalUsableArea.y2 -= wPreferences.icon_size;
866 #ifdef KWM_HINTS
868 WArea area;
870 if (wKWMGetUsableArea(scr, &area)) {
871 scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, area.x1);
872 scr->totalUsableArea.y1 = WMAX(scr->totalUsableArea.y1, area.y1);
873 scr->totalUsableArea.x2 = WMIN(scr->totalUsableArea.x2, area.x2);
874 scr->totalUsableArea.y2 = WMIN(scr->totalUsableArea.y2, area.y2);
877 #endif
879 #ifdef GNOME_STUFF
880 area = scr->reservedAreas;
882 while (area) {
883 int th, bh;
884 int lw, rw;
885 int w, h;
887 w = area->area.x2 - area->area.x1;
888 h = area->area.y2 - area->area.y1;
890 th = area->area.y1;
891 bh = scr->scr_height - area->area.y2;
892 lw = area->area.x1;
893 rw = scr->scr_width - area->area.x2;
895 if (WMIN(th, bh) < WMIN(lw, rw)) {
896 /* horizontal */
897 if (th < bh) {
898 /* on top */
899 if (scr->totalUsableArea.y1 < area->area.y2)
900 scr->totalUsableArea.y1 = area->area.y2;
901 } else {
902 /* on bottom */
903 if (scr->totalUsableArea.y2 > area->area.y1)
904 scr->totalUsableArea.y2 = area->area.y1;
906 } else {
907 /* vertical */
908 if (lw < rw) {
909 /* on left */
910 if (scr->totalUsableArea.x1 < area->area.x2)
911 scr->totalUsableArea.x1 = area->area.x2;
912 } else {
913 /* on right */
914 if (scr->totalUsableArea.x2 > area->area.x1)
915 scr->totalUsableArea.x2 = area->area.x1;
919 area = area->next;
921 #endif /* GNOME_STUFF */
923 if (scr->totalUsableArea.x2 - scr->totalUsableArea.x1 < scr->scr_width/2) {
924 scr->totalUsableArea.x2 = scr->usableArea.x2;
925 scr->totalUsableArea.x1 = scr->usableArea.x1;
927 if (scr->totalUsableArea.y2 - scr->totalUsableArea.y1 < scr->scr_height/2) {
928 scr->totalUsableArea.y2 = scr->usableArea.y2;
929 scr->totalUsableArea.y1 = scr->usableArea.y1;
932 #ifdef not_used
933 #ifdef KWM_HINTS
935 int i;
937 for (i = 0; i < scr->workspace_count; i++) {
938 wKWMSetUsableAreaHint(scr, i);
941 #endif
942 #endif
946 void
947 wScreenRestoreState(WScreen *scr)
949 proplist_t state;
950 char *path;
952 make_keys();
954 if (wScreenCount == 1)
955 path = wdefaultspathfordomain("WMState");
956 else {
957 char buf[16];
958 sprintf(buf, "WMState.%i", scr->screen);
959 path = wdefaultspathfordomain(buf);
961 scr->session_state = PLGetProplistWithPath(path);
962 free(path);
963 if (!scr->session_state && wScreenCount>1) {
964 char buf[16];
965 sprintf(buf, "WMState.%i", scr->screen);
966 path = wdefaultspathfordomain(buf);
967 scr->session_state = PLGetProplistWithPath(path);
968 free(path);
971 if (!wPreferences.flags.noclip) {
972 state = PLGetDictionaryEntry(scr->session_state, dClip);
973 scr->clip_icon = wClipRestoreState(scr, state);
976 wWorkspaceRestoreState(scr);
978 if (!wPreferences.flags.nodock) {
979 state = PLGetDictionaryEntry(scr->session_state, dDock);
980 scr->dock = wDockRestoreState(scr, state, WM_DOCK);
983 wScreenUpdateUsableArea(scr);
987 void
988 wScreenSaveState(WScreen *scr)
990 WWorkspaceState wstate;
991 WWindow *wwin;
992 char *str;
993 proplist_t path, old_state, foo;
994 CARD32 data[2];
997 make_keys();
1000 * Save current workspace, so can go back to it upon restart.
1002 wstate.workspace = scr->current_workspace;
1004 data[0] = wstate.flags;
1005 data[1] = wstate.workspace;
1007 XChangeProperty(dpy, scr->root_win, _XA_WINDOWMAKER_STATE,
1008 _XA_WINDOWMAKER_STATE, 32, PropModeReplace,
1009 (unsigned char *) data, 2);
1011 /* save state of windows */
1012 wwin = scr->focused_window;
1013 while (wwin) {
1014 wWindowSaveState(wwin);
1015 wwin = wwin->prev;
1019 if (wPreferences.flags.noupdates)
1020 return;
1023 old_state = scr->session_state;
1024 scr->session_state = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
1026 PLSetStringCmpHook(NULL);
1028 /* save dock state to file */
1029 if (!wPreferences.flags.nodock) {
1030 wDockSaveState(scr);
1031 } else {
1032 if ((foo = PLGetDictionaryEntry(old_state, dDock))!=NULL) {
1033 PLInsertDictionaryEntry(scr->session_state, dDock, foo);
1036 if (!wPreferences.flags.noclip) {
1037 wClipSaveState(scr);
1038 } else {
1039 if ((foo = PLGetDictionaryEntry(old_state, dClip))!=NULL) {
1040 PLInsertDictionaryEntry(scr->session_state, dClip, foo);
1044 wWorkspaceSaveState(scr, old_state);
1046 if (wPreferences.save_session_on_exit) {
1047 wSessionSaveState(scr);
1048 } else {
1049 if ((foo = PLGetDictionaryEntry(old_state, dApplications))!=NULL) {
1050 PLInsertDictionaryEntry(scr->session_state, dApplications, foo);
1052 if ((foo = PLGetDictionaryEntry(old_state, dWorkspace))!=NULL) {
1053 PLInsertDictionaryEntry(scr->session_state, dWorkspace, foo);
1057 /* clean up */
1058 PLSetStringCmpHook(StringCompareHook);
1060 wMenuSaveState(scr);
1062 if (wScreenCount == 1)
1063 str = wdefaultspathfordomain("WMState");
1064 else {
1065 char buf[16];
1066 sprintf(buf, "WMState.%i", scr->screen);
1067 str = wdefaultspathfordomain(buf);
1069 path = PLMakeString(str);
1070 free(str);
1071 PLSetFilename(scr->session_state, path);
1072 if (!PLSave(scr->session_state, YES)) {
1073 wwarning(_("could not save session state in %s"), PLGetString(path));
1075 PLRelease(path);
1076 PLRelease(old_state);
1082 wScreenBringInside(WScreen *scr, int *x, int *y, int width, int height)
1084 int moved = 0;
1085 int tol_w, tol_h;
1087 if (width > 20)
1088 tol_w = width/2;
1089 else
1090 tol_w = 20;
1092 if (height > 20)
1093 tol_h = height/2;
1094 else
1095 tol_h = 20;
1097 if (*x+width < 10)
1098 *x = -tol_w, moved = 1;
1099 else if (*x >= scr->scr_width - 10)
1100 *x = scr->scr_width - tol_w - 1, moved = 1;
1102 if (*y < -height + 10)
1103 *y = -tol_h, moved = 1;
1104 else if (*y >= scr->scr_height - 10)
1105 *y = scr->scr_height - tol_h - 1, moved = 1;
1107 return moved;