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;