1 /* screen.c - screen management
3 * Window Maker window manager
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
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,
30 #include <X11/Xutil.h>
31 #include <X11/Xatom.h>
33 #include <X11/extensions/shape.h>
35 #ifdef KEEP_XKB_LOCK_STATUS
36 #include <X11/XKBlib.h>
37 #endif /* KEEP_XKB_LOCK_STATUS */
39 #include <X11/extensions/Xrandr.h>
43 #include "WindowMaker.h"
44 #include "def_pixmaps.h"
51 #include "properties.h"
53 #include "resources.h"
54 #include "workspace.h"
62 #include <WINGs/WUtil.h>
66 #define EVENT_MASK (LeaveWindowMask|EnterWindowMask|PropertyChangeMask\
67 |SubstructureNotifyMask|PointerMotionMask \
68 |SubstructureRedirectMask|ButtonPressMask|ButtonReleaseMask\
69 |KeyPressMask|KeyReleaseMask)
71 /**** Global variables ****/
72 extern Cursor wCursor[WCUR_LAST];
73 extern WPreferences wPreferences;
74 extern Atom _XA_WINDOWMAKER_STATE;
75 extern Atom _XA_WINDOWMAKER_NOTICEBOARD;
77 extern int wScreenCount;
79 #ifdef KEEP_XKB_LOCK_STATUS
80 extern int wXkbSupported;
86 extern WDDomain *WDWindowMaker;
89 #define STIPPLE_WIDTH 2
90 #define STIPPLE_HEIGHT 2
91 static char STIPPLE_DATA[] = { 0x02, 0x01 };
93 static int CantManageScreen = 0;
95 static WMPropList *dApplications = NULL;
96 static WMPropList *dWorkspace;
97 static WMPropList *dDock;
98 static WMPropList *dClip;
100 static void make_keys(void)
102 if (dApplications != NULL)
105 dApplications = WMCreatePLString("Applications");
106 dWorkspace = WMCreatePLString("Workspace");
107 dDock = WMCreatePLString("Dock");
108 dClip = WMCreatePLString("Clip");
112 *----------------------------------------------------------------------
113 * alreadyRunningError--
114 * X error handler used to catch errors when trying to do
115 * XSelectInput() on the root window. These errors probably mean that
116 * there already is some other window manager running.
119 * Nothing, unless something really evil happens...
122 * CantManageScreen is set to 1;
123 *----------------------------------------------------------------------
125 static int alreadyRunningError(Display * dpy, XErrorEvent * error)
127 CantManageScreen = 1;
132 *----------------------------------------------------------------------
133 * allocButtonPixmaps--
134 * Allocate pixmaps used on window operation buttons (those in the
135 * titlebar). The pixmaps are linked to the program. If XPM is supported
136 * XPM pixmaps are used otherwise, equivalent bitmaps are used.
142 * Allocates shared pixmaps for the screen. These pixmaps should
143 * not be freed by anybody.
144 *----------------------------------------------------------------------
146 static void allocButtonPixmaps(WScreen * scr)
150 /* create predefined pixmaps */
151 pix = wPixmapCreateFromXPMData(scr, PRED_CLOSE_XPM);
154 scr->b_pixmaps[WBUT_CLOSE] = pix;
156 pix = wPixmapCreateFromXPMData(scr, PRED_BROKEN_CLOSE_XPM);
159 scr->b_pixmaps[WBUT_BROKENCLOSE] = pix;
161 pix = wPixmapCreateFromXPMData(scr, PRED_ICONIFY_XPM);
164 scr->b_pixmaps[WBUT_ICONIFY] = pix;
165 #ifdef XKB_BUTTON_HINT
166 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP1_XPM);
169 scr->b_pixmaps[WBUT_XKBGROUP1] = pix;
170 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP2_XPM);
173 scr->b_pixmaps[WBUT_XKBGROUP2] = pix;
174 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP3_XPM);
177 scr->b_pixmaps[WBUT_XKBGROUP3] = pix;
178 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP4_XPM);
181 scr->b_pixmaps[WBUT_XKBGROUP4] = pix;
184 pix = wPixmapCreateFromXPMData(scr, PRED_KILL_XPM);
187 scr->b_pixmaps[WBUT_KILL] = pix;
190 static void 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);
200 static WPixmap *make3Dots(WScreen * scr)
208 pix = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, wPreferences.icon_size, scr->w_depth);
209 XSetForeground(dpy, gc, scr->black_pixel);
210 XFillRectangle(dpy, pix, gc, 0, 0, wPreferences.icon_size, wPreferences.icon_size);
211 XSetForeground(dpy, gc, scr->white_pixel);
212 draw_dot(scr, pix, 4, wPreferences.icon_size - 6, gc);
213 draw_dot(scr, pix, 9, wPreferences.icon_size - 6, gc);
214 draw_dot(scr, pix, 14, wPreferences.icon_size - 6, gc);
216 mask = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, wPreferences.icon_size, 1);
218 gcv.graphics_exposures = False;
219 gc2 = XCreateGC(dpy, mask, GCForeground | GCGraphicsExposures, &gcv);
220 XFillRectangle(dpy, mask, gc2, 0, 0, wPreferences.icon_size, wPreferences.icon_size);
221 XSetForeground(dpy, gc2, 1);
222 XFillRectangle(dpy, mask, gc2, 4, wPreferences.icon_size - 6, 3, 2);
223 XFillRectangle(dpy, mask, gc2, 9, wPreferences.icon_size - 6, 3, 2);
224 XFillRectangle(dpy, mask, gc2, 14, wPreferences.icon_size - 6, 3, 2);
228 wpix = wPixmapCreate(scr, pix, mask);
234 static void allocGCs(WScreen * scr)
240 scr->stipple_bitmap = XCreateBitmapFromData(dpy, scr->w_win, STIPPLE_DATA, STIPPLE_WIDTH, STIPPLE_HEIGHT);
242 gcv.stipple = scr->stipple_bitmap;
243 gcv.foreground = scr->white_pixel;
244 gcv.fill_style = FillStippled;
245 gcv.graphics_exposures = False;
246 gcm = GCForeground | GCStipple | GCFillStyle | GCGraphicsExposures;
247 scr->stipple_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
249 /* selected icon border GCs */
250 gcv.function = GXcopy;
251 gcv.foreground = scr->white_pixel;
252 gcv.background = scr->black_pixel;
254 gcv.line_style = LineDoubleDash;
255 gcv.fill_style = FillSolid;
258 gcv.graphics_exposures = False;
260 gcm = GCFunction | GCGraphicsExposures;
261 gcm |= GCForeground | GCBackground;
262 gcm |= GCLineWidth | GCLineStyle;
264 gcm |= GCDashOffset | GCDashList;
266 scr->icon_select_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
268 scr->menu_title_color[0] = WMRetainColor(scr->white);
270 /* don't retain scr->black here because we may alter its alpha */
271 scr->mtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
272 scr->dtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
275 wGetColor(scr, DEF_FRAME_COLOR, &color);
276 gcv.function = GXxor;
277 /* this will raise the probability of the XORed color being different
278 * of the original color in PseudoColor when not all color cells are
280 if (DefaultVisual(dpy, scr->screen)->class == PseudoColor)
281 gcv.plane_mask = (1 << (scr->depth - 1)) | 1;
283 gcv.plane_mask = AllPlanes;
284 gcv.foreground = color.pixel;
285 if (gcv.foreground == 0)
287 gcv.line_width = DEF_FRAME_THICKNESS;
288 gcv.subwindow_mode = IncludeInferiors;
289 gcv.graphics_exposures = False;
290 scr->frame_gc = XCreateGC(dpy, scr->root_win, GCForeground | GCGraphicsExposures
291 | GCFunction | GCSubwindowMode | GCLineWidth | GCPlaneMask, &gcv);
294 gcv.foreground = color.pixel;
296 if (gcv.foreground == 0)
297 /* XOR:ing with a zero is not going to be of much use, so
298 in that case, we somewhat arbitrarily xor with 17 instead. */
301 gcv.function = GXxor;
302 gcv.subwindow_mode = IncludeInferiors;
304 gcv.cap_style = CapRound;
305 gcv.graphics_exposures = False;
306 gcm = GCForeground | GCFunction | GCSubwindowMode | GCLineWidth | GCCapStyle | GCGraphicsExposures;
307 scr->line_gc = XCreateGC(dpy, scr->root_win, gcm, &gcv);
309 scr->line_pixel = gcv.foreground;
312 gcv.foreground = scr->white_pixel;
313 gcv.background = scr->black_pixel;
314 gcv.graphics_exposures = False;
315 scr->copy_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
317 /* misc drawing GC */
318 gcv.graphics_exposures = False;
319 gcm = GCGraphicsExposures;
320 scr->draw_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
322 assert(scr->stipple_bitmap != None);
325 scr->mono_gc = XCreateGC(dpy, scr->stipple_bitmap, gcm, &gcv);
328 static void createPixmaps(WScreen * scr)
334 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_RADIO_INDICATOR_XBM_DATA,
335 (char *)MENU_RADIO_INDICATOR_XBM_DATA,
336 MENU_RADIO_INDICATOR_XBM_SIZE,
337 MENU_RADIO_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
340 scr->menu_radio_indicator = pix;
342 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_CHECK_INDICATOR_XBM_DATA,
343 (char *)MENU_CHECK_INDICATOR_XBM_DATA,
344 MENU_CHECK_INDICATOR_XBM_SIZE,
345 MENU_CHECK_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
348 scr->menu_check_indicator = pix;
350 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_MINI_INDICATOR_XBM_DATA,
351 (char *)MENU_MINI_INDICATOR_XBM_DATA,
352 MENU_MINI_INDICATOR_XBM_SIZE,
353 MENU_MINI_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
356 scr->menu_mini_indicator = pix;
358 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_HIDE_INDICATOR_XBM_DATA,
359 (char *)MENU_HIDE_INDICATOR_XBM_DATA,
360 MENU_HIDE_INDICATOR_XBM_SIZE,
361 MENU_HIDE_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
364 scr->menu_hide_indicator = pix;
366 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_SHADE_INDICATOR_XBM_DATA,
367 (char *)MENU_SHADE_INDICATOR_XBM_DATA,
368 MENU_SHADE_INDICATOR_XBM_SIZE,
369 MENU_SHADE_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
372 scr->menu_shade_indicator = pix;
374 image = wDefaultGetImage(scr, "Logo", "WMPanel");
377 wwarning(_("could not load logo image for panels: %s"), RMessageForError(RErrorCode));
379 WMSetApplicationIconImage(scr->wmscreen, image);
380 RReleaseImage(image);
383 scr->dock_dots = make3Dots(scr);
385 /* titlebar button pixmaps */
386 allocButtonPixmaps(scr);
390 *----------------------------------------------------------------------
391 * createInternalWindows--
392 * Creates some windows used internally by the program. One to
393 * receive input focus when no other window can get it and another
394 * to display window geometry information during window resize/move.
400 * Windows are created and some colors are allocated for the
402 *----------------------------------------------------------------------
404 static void createInternalWindows(WScreen * scr)
407 XSetWindowAttributes attribs;
409 /* InputOnly window to get the focus when no other window can get it */
410 vmask = CWEventMask | CWOverrideRedirect;
411 attribs.event_mask = KeyPressMask | FocusChangeMask;
412 attribs.override_redirect = True;
413 scr->no_focus_win = XCreateWindow(dpy, scr->root_win, -10, -10, 4, 4, 0, 0,
414 InputOnly, CopyFromParent, vmask, &attribs);
415 XSelectInput(dpy, scr->no_focus_win, KeyPressMask | KeyReleaseMask);
416 XMapWindow(dpy, scr->no_focus_win);
418 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
420 /* shadow window for dock buttons */
421 vmask = CWBorderPixel | CWBackPixmap | CWBackPixel | CWCursor | CWSaveUnder | CWOverrideRedirect;
422 attribs.border_pixel = scr->black_pixel;
423 attribs.save_under = True;
424 attribs.override_redirect = True;
425 attribs.background_pixmap = None;
426 attribs.background_pixel = scr->white_pixel;
427 attribs.cursor = wCursor[WCUR_DEFAULT];
429 attribs.colormap = scr->w_colormap;
431 XCreateWindow(dpy, scr->root_win, 0, 0, wPreferences.icon_size,
432 wPreferences.icon_size, 0, scr->w_depth, CopyFromParent, scr->w_visual, vmask, &attribs);
434 /* workspace name balloon for clip */
435 vmask = CWBackPixel | CWSaveUnder | CWOverrideRedirect | CWColormap | CWBorderPixel;
436 attribs.save_under = True;
437 attribs.override_redirect = True;
438 attribs.colormap = scr->w_colormap;
439 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
440 attribs.border_pixel = 0; /* do not care */
442 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
443 CopyFromParent, scr->w_visual, vmask, &attribs);
446 vmask = CWBackPixel | CWSaveUnder | CWOverrideRedirect | CWColormap | CWBorderPixel;
447 attribs.save_under = True;
448 attribs.override_redirect = True;
449 attribs.colormap = scr->w_colormap;
450 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
451 attribs.border_pixel = 0; /* do not care */
452 scr->workspace_name =
453 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
454 CopyFromParent, scr->w_visual, vmask, &attribs);
457 * If the window is clicked without having ButtonPress selected, the
458 * resulting event will have event.xbutton.window == root.
460 XSelectInput(dpy, scr->clip_balloon, ButtonPressMask);
464 static Bool aquireManagerSelection(WScreen * scr)
470 snprintf(buffer, sizeof(buffer), "WM_S%i", scr->screen);
471 scr->managerAtom = XInternAtom(dpy, buffer, False);
473 /* for race-conditions... */
476 /* if there is another manager running, don't try to replace it
477 * (for now, at least) */
478 if (XGetSelectionOwner(dpy, scr->managerAtom) != None) {
483 /* become the manager for this screen */
485 scr->managerWindow = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 1, 1, 0, 0, 0);
487 XSelectInput(dpy, scr->managerWindow, PropertyChangeMask);
488 /* get a timestamp */
489 XChangeProperty(dpy, scr->managerWindow, scr->managerAtom, XA_INTEGER, 32, PropModeAppend, NULL, 0);
491 XWindowEvent(dpy, scr->managerWindow, &ev);
492 if (ev.type == PropertyNotify) {
493 timestamp = ev.xproperty.time;
497 XSelectInput(dpy, scr->managerWindow, NoEvents);
498 XDeleteProperty(dpy, scr->managerWindow, scr->managerAtom);
500 XSetSelectionOwner(dpy, scr->managerAtom, scr->managerWindow, CurrentTime);
504 /* announce our arrival */
506 ev.xclient.type = ClientMessage;
507 ev.xclient.message_type = XInternAtom(dpy, "MANAGER", False);
508 ev.xclient.destination = scr->root_win;
509 ev.xclient.format = 32;
510 ev.xclient.data.l[0] = timestamp;
511 ev.xclient.data.l[1] = scr->managerAtom;
512 ev.xclient.data.l[2] = scr->managerWindow;
513 ev.xclient.data.l[3] = 0;
514 ev.xclient.data.l[4] = 0;
516 XSendEvent(dpy, scr->root_win, False, StructureNotify, &ev);
524 *----------------------------------------------------------------------
526 * Initializes the window manager for the given screen and
527 * allocates a WScreen descriptor for it. Many resources are allocated
528 * for the screen and the root window is setup appropriately.
531 * The WScreen descriptor for the screen.
534 * Many resources are allocated and the IconSize property is
535 * set on the root window.
536 * The program can be aborted if some fatal error occurs.
538 * TODO: User specifiable visual.
539 *----------------------------------------------------------------------
541 WScreen *wScreenInit(int screen_number)
544 XIconSize icon_size[1];
545 RContextAttributes rattr;
547 XErrorHandler oldHandler;
550 scr = wmalloc(sizeof(WScreen));
551 memset(scr, 0, sizeof(WScreen));
553 scr->stacking_list = WMCreateTreeBag();
555 /* initialize globals */
556 scr->screen = screen_number;
557 scr->root_win = RootWindow(dpy, screen_number);
558 scr->depth = DefaultDepth(dpy, screen_number);
559 scr->colormap = DefaultColormap(dpy, screen_number);
561 scr->scr_width = WidthOfScreen(ScreenOfDisplay(dpy, screen_number));
562 scr->scr_height = HeightOfScreen(ScreenOfDisplay(dpy, screen_number));
566 scr->usableArea = (WArea *) wmalloc(sizeof(WArea) * wXineramaHeads(scr));
567 scr->totalUsableArea = (WArea *) wmalloc(sizeof(WArea) * wXineramaHeads(scr));
569 for (i = 0; i < wXineramaHeads(scr); ++i) {
570 WMRect rect = wGetRectForHead(scr, i);
571 scr->usableArea[i].x1 = scr->totalUsableArea[i].x1 = rect.pos.x;
572 scr->usableArea[i].y1 = scr->totalUsableArea[i].y1 = rect.pos.y;
573 scr->usableArea[i].x2 = scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
574 scr->usableArea[i].y2 = scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
577 scr->fakeGroupLeaders = WMCreateArray(16);
580 if (!aquireManagerSelection(scr)) {
586 CantManageScreen = 0;
587 oldHandler = XSetErrorHandler((XErrorHandler) alreadyRunningError);
589 event_mask = EVENT_MASK;
591 if (wPreferences.disable_root_mouse) {
592 event_mask &= ~(ButtonPressMask | ButtonReleaseMask);
595 XSelectInput(dpy, scr->root_win, event_mask);
597 #ifdef KEEP_XKB_LOCK_STATUS
598 /* Only GroupLock doesn't work correctly in my system since right-alt
599 * can change mode while holding it too - ]d
602 XkbSelectEvents(dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask);
604 #endif /* KEEP_XKB_LOCK_STATUS */
608 XRRSelectInput(dpy, scr->root_win, RRScreenChangeNotifyMask);
612 XSetErrorHandler(oldHandler);
614 if (CantManageScreen) {
619 XDefineCursor(dpy, scr->root_win, wCursor[WCUR_ROOT]);
621 /* screen descriptor for raster graphic library */
622 rattr.flags = RC_RenderMode | RC_ColorsPerChannel | RC_StandardColormap;
623 rattr.render_mode = wPreferences.no_dithering ? RBestMatchRendering : RDitheredRendering;
625 /* if the std colormap stuff works ok, this will be ignored */
626 rattr.colors_per_channel = wPreferences.cmap_size;
627 if (rattr.colors_per_channel < 2)
628 rattr.colors_per_channel = 2;
630 /* will only be accounted for in PseudoColor */
631 if (wPreferences.flags.create_stdcmap) {
632 rattr.standard_colormap_mode = RCreateStdColormap;
634 rattr.standard_colormap_mode = RUseStdColormap;
637 if (getWVisualID(screen_number) >= 0) {
638 rattr.flags |= RC_VisualID;
639 rattr.visualid = getWVisualID(screen_number);
642 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
644 if (!scr->rcontext && RErrorCode == RERR_STDCMAPFAIL) {
645 wwarning(RMessageForError(RErrorCode));
647 rattr.flags &= ~RC_StandardColormap;
648 rattr.standard_colormap_mode = RUseStdColormap;
650 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
653 if (!scr->rcontext) {
654 wwarning(_("could not initialize graphics library context: %s"), RMessageForError(RErrorCode));
660 formats = RSupportedFileFormats();
662 for (i = 0; formats[i] != NULL; i++) {
663 if (strcmp(formats[i], "TIFF") == 0) {
664 scr->flags.supports_tiff = 1;
671 scr->w_win = scr->rcontext->drawable;
672 scr->w_visual = scr->rcontext->visual;
673 scr->w_depth = scr->rcontext->depth;
674 scr->w_colormap = scr->rcontext->cmap;
676 /* create screen descriptor for WINGs */
677 scr->wmscreen = WMCreateScreenWithRContext(dpy, screen_number, scr->rcontext);
679 if (!scr->wmscreen) {
680 wfatal(_("could not initialize WINGs widget set"));
684 scr->black = WMBlackColor(scr->wmscreen);
685 scr->white = WMWhiteColor(scr->wmscreen);
686 scr->gray = WMGrayColor(scr->wmscreen);
687 scr->darkGray = WMDarkGrayColor(scr->wmscreen);
689 scr->black_pixel = WMColorPixel(scr->black); /*scr->rcontext->black; */
690 scr->white_pixel = WMColorPixel(scr->white); /*scr->rcontext->white; */
691 scr->light_pixel = WMColorPixel(scr->gray);
692 scr->dark_pixel = WMColorPixel(scr->darkGray);
696 /* frame boder color */
697 wGetColor(scr, FRAME_BORDER_COLOR, &xcol);
698 scr->frame_border_pixel = xcol.pixel;
701 /* create GCs with default values */
704 /* for our window manager info notice board. Need to
705 * create before reading the defaults, because it will be used there.
707 scr->info_window = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, 0, 0);
709 /* read defaults for this screen */
710 wReadDefaults(scr, WDWindowMaker->dictionary);
712 createInternalWindows(scr);
714 wNETWMInitStuff(scr);
716 /* create initial workspace */
719 /* create shared pixmaps */
722 /* set icon sizes we can accept from clients */
723 icon_size[0].min_width = 8;
724 icon_size[0].min_height = 8;
725 icon_size[0].max_width = wPreferences.icon_size - 4;
726 icon_size[0].max_height = wPreferences.icon_size - 4;
727 icon_size[0].width_inc = 1;
728 icon_size[0].height_inc = 1;
729 XSetIconSizes(dpy, scr->root_win, icon_size, 1);
731 /* setup WindowMaker protocols property in the root window */
732 PropSetWMakerProtocols(scr->root_win);
734 /* setup our noticeboard */
735 XChangeProperty(dpy, scr->info_window, _XA_WINDOWMAKER_NOTICEBOARD,
736 XA_WINDOW, 32, PropModeReplace, (unsigned char *)&scr->info_window, 1);
737 XChangeProperty(dpy, scr->root_win, _XA_WINDOWMAKER_NOTICEBOARD,
738 XA_WINDOW, 32, PropModeReplace, (unsigned char *)&scr->info_window, 1);
741 /* initialize balloon text stuff */
742 wBalloonInitialize(scr);
745 scr->info_text_font = WMBoldSystemFontOfSize(scr->wmscreen, 12);
747 scr->tech_draw_font = XLoadQueryFont(dpy, "-adobe-helvetica-bold-r-*-*-12-*-*-*-*-*-*-*");
748 if (!scr->tech_draw_font)
749 scr->tech_draw_font = XLoadQueryFont(dpy, "fixed");
751 scr->gview = WCreateGeometryView(scr->wmscreen);
752 WMRealizeWidget(scr->gview);
754 wScreenUpdateUsableArea(scr);
759 void wScreenUpdateUsableArea(WScreen * scr)
762 * scr->totalUsableArea[] will become the usableArea used for Windowplacement,
763 * scr->usableArea[] will be used for iconplacement, hence no iconyard nor
768 unsigned long best_area = 0, tmp_area;
770 int dock_head = scr->xine_info.primary_head;
774 rect.pos.x = scr->dock->x_pos;
775 rect.pos.y = scr->dock->y_pos;
776 rect.size.width = wPreferences.icon_size;
777 rect.size.height = wPreferences.icon_size;
778 dock_head = wGetHeadForRect(scr, rect);
781 for (i = 0; i < wXineramaHeads(scr); ++i) {
782 WMRect rect = wGetRectForHead(scr, i);
783 scr->totalUsableArea[i].x1 = rect.pos.x;
784 scr->totalUsableArea[i].y1 = rect.pos.y;
785 scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
786 scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
788 if (scr->dock && dock_head == i && (!scr->dock->lowered || wPreferences.no_window_over_dock)) {
789 int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
791 if (scr->dock->on_right_side) {
792 scr->totalUsableArea[i].x2 -= offset;
794 scr->totalUsableArea[i].x1 += offset;
800 if (wNETWMGetUsableArea(scr, i, &area)) {
801 scr->totalUsableArea[i].x1 = WMAX(scr->totalUsableArea[i].x1, area.x1);
802 scr->totalUsableArea[i].y1 = WMAX(scr->totalUsableArea[i].y1, area.y1);
803 scr->totalUsableArea[i].x2 = WMIN(scr->totalUsableArea[i].x2, area.x2);
804 scr->totalUsableArea[i].y2 = WMIN(scr->totalUsableArea[i].y2, area.y2);
808 scr->usableArea[i] = scr->totalUsableArea[i];
811 printf("usableArea[%d]: %d %d %d %d\n", i,
812 scr->usableArea[i].x1, scr->usableArea[i].x2, scr->usableArea[i].y1, scr->usableArea[i].y2);
815 if (wPreferences.no_window_over_icons) {
816 if (wPreferences.icon_yard & IY_VERT) {
817 if (wPreferences.icon_yard & IY_RIGHT) {
818 scr->totalUsableArea[i].x2 -= wPreferences.icon_size;
820 scr->totalUsableArea[i].x1 += wPreferences.icon_size;
823 if (wPreferences.icon_yard & IY_TOP) {
824 scr->totalUsableArea[i].y1 += wPreferences.icon_size;
826 scr->totalUsableArea[i].y2 -= wPreferences.icon_size;
831 if (scr->totalUsableArea[i].x2 - scr->totalUsableArea[i].x1 < rect.size.width / 2) {
832 scr->totalUsableArea[i].x1 = rect.pos.x;
833 scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
836 if (scr->totalUsableArea[i].y2 - scr->totalUsableArea[i].y1 < rect.size.height / 2) {
837 scr->totalUsableArea[i].y1 = rect.pos.y;
838 scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
841 tmp_area = (scr->totalUsableArea[i].x2 - scr->totalUsableArea[i].x1) *
842 (scr->totalUsableArea[i].y2 - scr->totalUsableArea[i].y1);
844 if (tmp_area > best_area) {
845 best_area = tmp_area;
846 area = scr->totalUsableArea[i];
850 unsigned size = wPreferences.workspace_border_size;
851 unsigned position = wPreferences.workspace_border_position;
853 if (size > 0 && position != WB_NONE) {
854 if (position & WB_LEFTRIGHT) {
855 scr->totalUsableArea[i].x1 += size;
856 scr->totalUsableArea[i].x2 -= size;
858 if (position & WB_TOPBOTTOM) {
859 scr->totalUsableArea[i].y1 += size;
860 scr->totalUsableArea[i].y2 -= size;
866 wNETWMUpdateWorkarea(scr, area);
868 if (wPreferences.auto_arrange_icons)
869 wArrangeIcons(scr, True);
872 void wScreenRestoreState(WScreen * scr)
877 OpenRootMenu(scr, -10000, -10000, False);
878 wMenuUnmap(scr->root_menu);
882 if (wScreenCount == 1) {
883 path = wdefaultspathfordomain("WMState");
886 snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
887 path = wdefaultspathfordomain(buf);
889 scr->session_state = WMReadPropListFromFile(path);
891 if (!scr->session_state && wScreenCount > 1) {
892 path = wdefaultspathfordomain("WMState");
893 scr->session_state = WMReadPropListFromFile(path);
897 if (!scr->session_state) {
898 scr->session_state = WMCreatePLDictionary(NULL, NULL);
901 if (!wPreferences.flags.nodock) {
902 state = WMGetFromPLDictionary(scr->session_state, dDock);
903 scr->dock = wDockRestoreState(scr, state, WM_DOCK);
906 if (!wPreferences.flags.noclip) {
907 state = WMGetFromPLDictionary(scr->session_state, dClip);
908 scr->clip_icon = wClipRestoreState(scr, state);
911 wWorkspaceRestoreState(scr);
913 wScreenUpdateUsableArea(scr);
916 void wScreenSaveState(WScreen * scr)
920 WMPropList *old_state, *foo;
924 /* save state of windows */
925 wwin = scr->focused_window;
927 wWindowSaveState(wwin);
931 if (wPreferences.flags.noupdates)
934 old_state = scr->session_state;
935 scr->session_state = WMCreatePLDictionary(NULL, NULL);
937 WMPLSetCaseSensitive(True);
939 /* save dock state to file */
940 if (!wPreferences.flags.nodock) {
941 wDockSaveState(scr, old_state);
943 if ((foo = WMGetFromPLDictionary(old_state, dDock)) != NULL) {
944 WMPutInPLDictionary(scr->session_state, dDock, foo);
947 if (!wPreferences.flags.noclip) {
950 if ((foo = WMGetFromPLDictionary(old_state, dClip)) != NULL) {
951 WMPutInPLDictionary(scr->session_state, dClip, foo);
955 wWorkspaceSaveState(scr, old_state);
957 if (wPreferences.save_session_on_exit) {
958 wSessionSaveState(scr);
960 if ((foo = WMGetFromPLDictionary(old_state, dApplications)) != NULL) {
961 WMPutInPLDictionary(scr->session_state, dApplications, foo);
963 if ((foo = WMGetFromPLDictionary(old_state, dWorkspace)) != NULL) {
964 WMPutInPLDictionary(scr->session_state, dWorkspace, foo);
969 WMPLSetCaseSensitive(False);
973 if (wScreenCount == 1) {
974 str = wdefaultspathfordomain("WMState");
977 snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
978 str = wdefaultspathfordomain(buf);
980 if (!WMWritePropListToFile(scr->session_state, str)) {
981 wsyserror(_("could not save session state in %s"), str);
984 WMReleasePropList(old_state);
987 int wScreenBringInside(WScreen * scr, int *x, int *y, int width, int height)
992 * With respect to the head that contains most of the window.
994 int sx1, sy1, sx2, sy2;
1001 rect.size.width = width;
1002 rect.size.height = height;
1004 head = wGetRectPlacementInfo(scr, rect, &flags);
1005 rect = wGetRectForHead(scr, head);
1009 sx2 = sx1 + rect.size.width;
1010 sy2 = sy1 + rect.size.height;
1012 #if 0 /* NOTE: gives funky group movement */
1013 if (flags & XFLAG_MULTIPLE) {
1015 * since we span multiple heads, pull window totaly inside
1018 *x = sx1, moved = 1;
1019 else if (*x + width > sx2)
1020 *x = sx2 - width, moved = 1;
1023 *y = sy1, moved = 1;
1024 else if (*y + height > sy2)
1025 *y = sy2 - height, moved = 1;
1041 if (*x + width < sx1 + 10)
1042 *x = sx1 - tol_w, moved = 1;
1043 else if (*x >= sx2 - 10)
1044 *x = sx2 - tol_w - 1, moved = 1;
1046 if (*y < sy1 - height + 10)
1047 *y = sy1 - tol_h, moved = 1;
1048 else if (*y >= sy2 - 10)
1049 *y = sy2 - tol_h - 1, moved = 1;
1054 int wScreenKeepInside(WScreen * scr, int *x, int *y, int width, int height)
1057 int sx1, sy1, sx2, sy2;
1063 rect.size.width = width;
1064 rect.size.height = height;
1066 head = wGetHeadForRect(scr, rect);
1067 rect = wGetRectForHead(scr, head);
1071 sx2 = sx1 + rect.size.width;
1072 sy2 = sy1 + rect.size.height;
1075 *x = sx1, moved = 1;
1076 else if (*x + width > sx2)
1077 *x = sx2 - width, moved = 1;
1080 *y = sy1, moved = 1;
1081 else if (*y + height > sy2)
1082 *y = sy2 - height, moved = 1;