1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <string.h>
21 #include <stdlib.h>
22
23 #include <i18nlangtag/languagetag.hxx>
24 #include <rtl/locale.h>
25
26 #include <osl/thread.h>
27 #include <osl/process.h>
28 #include <sal/macros.h>
29 #include <vcl/configsettings.hxx>
30
31 #include <unx/wmadaptor.hxx>
32 #include <unx/saldisp.hxx>
33 #include <unx/salframe.h>
34
35 #include <X11/Xlib.h>
36 #include <X11/Xutil.h>
37 #include <X11/Xatom.h>
38
39 namespace vcl_sal {
40
41 class NetWMAdaptor : public WMAdaptor
42 {
43 void setNetWMState( X11SalFrame* pFrame ) const;
44 void initAtoms();
45 virtual bool isValid() const override;
46 public:
47 explicit NetWMAdaptor( SalDisplay* );
48
49 virtual void setWMName( X11SalFrame* pFrame, const OUString& rWMName ) const override;
50 virtual void maximizeFrame( X11SalFrame* pFrame, bool bHorizontal = true, bool bVertical = true ) const override;
51 virtual void shade( X11SalFrame* pFrame, bool bToShaded ) const override;
52 virtual void setFrameTypeAndDecoration( X11SalFrame* pFrame, WMWindowType eType, int nDecorationFlags, X11SalFrame* pTransientFrame ) const override;
53 virtual void enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const override;
54 virtual int handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const override;
55 virtual void showFullScreen( X11SalFrame* pFrame, bool bFullScreen ) const override;
56 virtual void frameIsMapping( X11SalFrame* pFrame ) const override;
57 virtual void setUserTime( X11SalFrame* i_pFrame, long i_nUserTime ) const override;
58 };
59
60 class GnomeWMAdaptor : public WMAdaptor
61 {
62 bool m_bValid;
63
64 void setGnomeWMState( X11SalFrame* pFrame ) const;
65 void initAtoms();
66 virtual bool isValid() const override;
67 public:
68 explicit GnomeWMAdaptor( SalDisplay * );
69
70 virtual void maximizeFrame( X11SalFrame* pFrame, bool bHorizontal = true, bool bVertical = true ) const override;
71 virtual void shade( X11SalFrame* pFrame, bool bToShaded ) const override;
72 virtual void enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const override;
73 virtual int handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const override;
74 };
75
76 }
77
78 using namespace vcl_sal;
79
80 struct WMAdaptorProtocol
81 {
82 const char* pProtocol;
83 int nProtocol;
84 };
85
86 /*
87 * table must be sorted ascending in strings
88 * since it is use with bsearch
89 */
90 static const WMAdaptorProtocol aProtocolTab[] =
91 {
92 { "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", WMAdaptor::KDE_NET_WM_WINDOW_TYPE_OVERRIDE },
93 { "_NET_ACTIVE_WINDOW", WMAdaptor::NET_ACTIVE_WINDOW },
94 { "_NET_CURRENT_DESKTOP", WMAdaptor::NET_CURRENT_DESKTOP },
95 { "_NET_NUMBER_OF_DESKTOPS", WMAdaptor::NET_NUMBER_OF_DESKTOPS },
96 { "_NET_WM_DESKTOP", WMAdaptor::NET_WM_DESKTOP },
97 { "_NET_WM_ICON", WMAdaptor::NET_WM_ICON },
98 { "_NET_WM_ICON_NAME", WMAdaptor::NET_WM_ICON_NAME },
99 { "_NET_WM_PING", WMAdaptor::NET_WM_PING },
100 { "_NET_WM_STATE", WMAdaptor::NET_WM_STATE },
101 { "_NET_WM_STATE_ABOVE", WMAdaptor::NET_WM_STATE_STAYS_ON_TOP },
102 { "_NET_WM_STATE_FULLSCREEN", WMAdaptor::NET_WM_STATE_FULLSCREEN },
103 { "_NET_WM_STATE_MAXIMIZED_HORIZ", WMAdaptor::NET_WM_STATE_MAXIMIZED_HORZ }, // common bug in e.g. older kwin and sawfish implementations
104 { "_NET_WM_STATE_MAXIMIZED_HORZ", WMAdaptor::NET_WM_STATE_MAXIMIZED_HORZ },
105 { "_NET_WM_STATE_MAXIMIZED_VERT", WMAdaptor::NET_WM_STATE_MAXIMIZED_VERT },
106 { "_NET_WM_STATE_MODAL", WMAdaptor::NET_WM_STATE_MODAL },
107 { "_NET_WM_STATE_SHADED", WMAdaptor::NET_WM_STATE_SHADED },
108 { "_NET_WM_STATE_SKIP_PAGER", WMAdaptor::NET_WM_STATE_SKIP_PAGER },
109 { "_NET_WM_STATE_SKIP_TASKBAR", WMAdaptor::NET_WM_STATE_SKIP_TASKBAR },
110 { "_NET_WM_STATE_STAYS_ON_TOP", WMAdaptor::NET_WM_STATE_STAYS_ON_TOP },
111 { "_NET_WM_STATE_STICKY", WMAdaptor::NET_WM_STATE_STICKY },
112 { "_NET_WM_STRUT", WMAdaptor::NET_WM_STRUT },
113 { "_NET_WM_STRUT_PARTIAL", WMAdaptor::NET_WM_STRUT_PARTIAL },
114 { "_NET_WM_WINDOW_TYPE", WMAdaptor::NET_WM_WINDOW_TYPE },
115 { "_NET_WM_WINDOW_TYPE_DESKTOP", WMAdaptor::NET_WM_WINDOW_TYPE_DESKTOP },
116 { "_NET_WM_WINDOW_TYPE_DIALOG", WMAdaptor::NET_WM_WINDOW_TYPE_DIALOG },
117 { "_NET_WM_WINDOW_TYPE_DOCK", WMAdaptor::NET_WM_WINDOW_TYPE_DOCK },
118 { "_NET_WM_WINDOW_TYPE_MENU", WMAdaptor::NET_WM_WINDOW_TYPE_MENU },
119 { "_NET_WM_WINDOW_TYPE_NORMAL", WMAdaptor::NET_WM_WINDOW_TYPE_NORMAL },
120 { "_NET_WM_WINDOW_TYPE_SPLASH", WMAdaptor::NET_WM_WINDOW_TYPE_SPLASH },
121 { "_NET_WM_WINDOW_TYPE_SPLASHSCREEN", WMAdaptor::NET_WM_WINDOW_TYPE_SPLASH }, // bug in Metacity 2.4.1
122 { "_NET_WM_WINDOW_TYPE_TOOLBAR", WMAdaptor::NET_WM_WINDOW_TYPE_TOOLBAR },
123 { "_NET_WM_WINDOW_TYPE_UTILITY", WMAdaptor::NET_WM_WINDOW_TYPE_UTILITY },
124 { "_NET_WORKAREA", WMAdaptor::NET_WORKAREA },
125 { "_WIN_APP_STATE", WMAdaptor::WIN_APP_STATE },
126 { "_WIN_CLIENT_LIST", WMAdaptor::WIN_CLIENT_LIST },
127 { "_WIN_EXPANDED_SIZE", WMAdaptor::WIN_EXPANDED_SIZE },
128 { "_WIN_HINTS", WMAdaptor::WIN_HINTS },
129 { "_WIN_ICONS", WMAdaptor::WIN_ICONS },
130 { "_WIN_LAYER", WMAdaptor::WIN_LAYER },
131 { "_WIN_STATE", WMAdaptor::WIN_STATE },
132 { "_WIN_WORKSPACE", WMAdaptor::WIN_WORKSPACE },
133 { "_WIN_WORKSPACE_COUNT", WMAdaptor::WIN_WORKSPACE_COUNT }
134 };
135
136 /*
137 * table containing atoms to get anyway
138 */
139
140 static const WMAdaptorProtocol aAtomTab[] =
141 {
142 { "WM_STATE", WMAdaptor::WM_STATE },
143 { "_MOTIF_WM_HINTS", WMAdaptor::MOTIF_WM_HINTS },
144 { "WM_PROTOCOLS", WMAdaptor::WM_PROTOCOLS },
145 { "WM_DELETE_WINDOW", WMAdaptor::WM_DELETE_WINDOW },
146 { "WM_TAKE_FOCUS", WMAdaptor::WM_TAKE_FOCUS },
147 { "WM_COMMAND", WMAdaptor::WM_COMMAND },
148 { "WM_CLIENT_LEADER", WMAdaptor::WM_CLIENT_LEADER },
149 { "WM_LOCALE_NAME", WMAdaptor::WM_LOCALE_NAME },
150 { "WM_TRANSIENT_FOR", WMAdaptor::WM_TRANSIENT_FOR },
151 { "SAL_QUITEVENT", WMAdaptor::SAL_QUITEVENT },
152 { "SAL_USEREVENT", WMAdaptor::SAL_USEREVENT },
153 { "SAL_EXTTEXTEVENT", WMAdaptor::SAL_EXTTEXTEVENT },
154 { "SAL_GETTIMEEVENT", WMAdaptor::SAL_GETTIMEEVENT },
155 { "VCL_SYSTEM_SETTINGS", WMAdaptor::VCL_SYSTEM_SETTINGS },
156 { "_XSETTINGS_SETTINGS", WMAdaptor::XSETTINGS },
157 { "_XEMBED", WMAdaptor::XEMBED },
158 { "_XEMBED_INFO", WMAdaptor::XEMBED_INFO },
159 { "_NET_WM_USER_TIME", WMAdaptor::NET_WM_USER_TIME },
160 { "_NET_WM_PID", WMAdaptor::NET_WM_PID }
161 };
162
163 extern "C" {
compareProtocol(const void * pLeft,const void * pRight)164 static int compareProtocol( const void* pLeft, const void* pRight )
165 {
166 return strcmp( static_cast<const WMAdaptorProtocol*>(pLeft)->pProtocol, static_cast<const WMAdaptorProtocol*>(pRight)->pProtocol );
167 }
168 }
169
createWMAdaptor(SalDisplay * pSalDisplay)170 std::unique_ptr<WMAdaptor> WMAdaptor::createWMAdaptor( SalDisplay* pSalDisplay )
171 {
172 std::unique_ptr<WMAdaptor> pAdaptor;
173
174 // try a NetWM
175 pAdaptor.reset(new NetWMAdaptor( pSalDisplay ));
176 if( ! pAdaptor->isValid() )
177 {
178 pAdaptor.reset();
179 }
180 #if OSL_DEBUG_LEVEL > 1
181 else
182 fprintf( stderr, "WM supports extended WM hints\n" );
183 #endif
184
185 // try a GnomeWM
186 if( ! pAdaptor )
187 {
188 pAdaptor.reset(new GnomeWMAdaptor( pSalDisplay ));
189 if( ! pAdaptor->isValid() )
190 {
191 pAdaptor.reset();
192 }
193 #if OSL_DEBUG_LEVEL > 1
194 else
195 fprintf( stderr, "WM supports GNOME WM hints\n" );
196 #endif
197 }
198
199 if( ! pAdaptor )
200 pAdaptor.reset(new WMAdaptor( pSalDisplay ));
201
202 #if OSL_DEBUG_LEVEL > 1
203 fprintf(stderr, "Window Manager's name is \"%s\"\n",
204 OUStringToOString(pAdaptor->getWindowManagerName(),
205 RTL_TEXTENCODING_UTF8).getStr());
206 #endif
207 return pAdaptor;
208 }
209
210 /*
211 * WMAdaptor constructor
212 */
213
WMAdaptor(SalDisplay * pDisplay)214 WMAdaptor::WMAdaptor( SalDisplay* pDisplay ) :
215 m_pSalDisplay( pDisplay ),
216 m_bEnableAlwaysOnTopWorks( false ),
217 m_bLegacyPartialFullscreen( false ),
218 m_nWinGravity( StaticGravity ),
219 m_nInitWinGravity( StaticGravity ),
220 m_bWMshouldSwitchWorkspace( true ),
221 m_bWMshouldSwitchWorkspaceInit( false )
222 {
223 Atom aRealType = None;
224 int nFormat = 8;
225 unsigned long nItems = 0;
226 unsigned long nBytesLeft = 0;
227 unsigned char* pProperty = nullptr;
228
229 // default desktops
230 m_nDesktops = 1;
231 m_aWMWorkAreas = ::std::vector< tools::Rectangle >
232 ( 1, tools::Rectangle( Point(), m_pSalDisplay->GetScreenSize( m_pSalDisplay->GetDefaultXScreen() ) ) );
233 m_bEqualWorkAreas = true;
234
235 memset( m_aWMAtoms, 0, sizeof( m_aWMAtoms ) );
236 m_pDisplay = m_pSalDisplay->GetDisplay();
237
238 initAtoms();
239 getNetWmName(); // try to discover e.g. Sawfish
240
241 if( m_aWMName.isEmpty() )
242 {
243 // check for ReflectionX wm (as it needs a workaround in Windows mode
244 Atom aRwmRunning = XInternAtom( m_pDisplay, "RWM_RUNNING", True );
245 if( aRwmRunning != None &&
246 XGetWindowProperty( m_pDisplay,
247 m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ),
248 aRwmRunning,
249 0, 32,
250 False,
251 aRwmRunning,
252 &aRealType,
253 &nFormat,
254 &nItems,
255 &nBytesLeft,
256 &pProperty ) == 0 )
257 {
258 if( aRealType == aRwmRunning )
259 m_aWMName = "ReflectionX";
260 XFree( pProperty );
261 }
262 else if( (aRwmRunning = XInternAtom( m_pDisplay, "_WRQ_WM_RUNNING", True )) != None &&
263 XGetWindowProperty( m_pDisplay,
264 m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ),
265 aRwmRunning,
266 0, 32,
267 False,
268 XA_STRING,
269 &aRealType,
270 &nFormat,
271 &nItems,
272 &nBytesLeft,
273 &pProperty ) == 0 )
274 {
275 if( aRealType == XA_STRING )
276 m_aWMName = "ReflectionX Windows";
277 XFree( pProperty );
278 }
279 }
280 if( m_aWMName.isEmpty() )
281 {
282 Atom aTTAPlatform = XInternAtom( m_pDisplay, "TTA_CLIENT_PLATFORM", True );
283 if( aTTAPlatform != None &&
284 XGetWindowProperty( m_pDisplay,
285 m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ),
286 aTTAPlatform,
287 0, 32,
288 False,
289 XA_STRING,
290 &aRealType,
291 &nFormat,
292 &nItems,
293 &nBytesLeft,
294 &pProperty ) == 0 )
295 {
296 if( aRealType == XA_STRING )
297 {
298 m_aWMName = "Tarantella";
299 // #i62319# pretend that AlwaysOnTop works since
300 // the alwaysontop workaround in salframe.cxx results
301 // in a raise/lower loop on a Windows tarantella client
302 // FIXME: this property contains an identification string that
303 // in theory should be good enough to recognize running on a
304 // Windows client; however this string does not seem to be
305 // documented as well as the property itself.
306 m_bEnableAlwaysOnTopWorks = true;
307 }
308 XFree( pProperty );
309 }
310 }
311 }
312
313 /*
314 * WMAdaptor destructor
315 */
316
~WMAdaptor()317 WMAdaptor::~WMAdaptor()
318 {
319 }
320
321 /*
322 * NetWMAdaptor constructor
323 */
324
NetWMAdaptor(SalDisplay * pSalDisplay)325 NetWMAdaptor::NetWMAdaptor( SalDisplay* pSalDisplay ) :
326 WMAdaptor( pSalDisplay )
327 {
328 // currently all _NET WMs do transient like expected
329
330 Atom aRealType = None;
331 int nFormat = 8;
332 unsigned long nItems = 0;
333 unsigned long nBytesLeft = 0;
334 unsigned char* pProperty = nullptr;
335
336 initAtoms();
337
338 // check for NetWM
339 bool bNetWM = getNetWmName();
340 if( bNetWM
341 && XGetWindowProperty( m_pDisplay,
342 m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ),
343 m_aWMAtoms[ NET_SUPPORTED ],
344 0, 0,
345 False,
346 XA_ATOM,
347 &aRealType,
348 &nFormat,
349 &nItems,
350 &nBytesLeft,
351 &pProperty ) == 0
352 && aRealType == XA_ATOM
353 && nFormat == 32
354 )
355 {
356 if( pProperty )
357 {
358 XFree( pProperty );
359 pProperty = nullptr;
360 }
361 // collect supported protocols
362 if( XGetWindowProperty( m_pDisplay,
363 m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ),
364 m_aWMAtoms[ NET_SUPPORTED ],
365 0, nBytesLeft/4,
366 False,
367 XA_ATOM,
368 &aRealType,
369 &nFormat,
370 &nItems,
371 &nBytesLeft,
372 &pProperty ) == 0
373 && nItems
374 )
375 {
376 Atom* pAtoms = reinterpret_cast<Atom*>(pProperty);
377 char** pAtomNames = static_cast<char**>(alloca( sizeof(char*)*nItems ));
378 if( XGetAtomNames( m_pDisplay, pAtoms, nItems, pAtomNames ) )
379 {
380 #if OSL_DEBUG_LEVEL > 1
381 fprintf( stderr, "supported protocols:\n" );
382 #endif
383 for( unsigned long i = 0; i < nItems; i++ )
384 {
385 // #i80971# protect against invalid atoms
386 if( pAtomNames[i] == nullptr )
387 continue;
388
389 WMAdaptorProtocol aSearch;
390 aSearch.pProtocol = pAtomNames[i];
391 WMAdaptorProtocol* pMatch = static_cast<WMAdaptorProtocol*>(
392 bsearch( &aSearch,
393 aProtocolTab,
394 SAL_N_ELEMENTS( aProtocolTab ),
395 sizeof( struct WMAdaptorProtocol ),
396 compareProtocol ));
397 if( pMatch )
398 {
399 m_aWMAtoms[ pMatch->nProtocol ] = pAtoms[ i ];
400 if( pMatch->nProtocol == NET_WM_STATE_STAYS_ON_TOP )
401 m_bEnableAlwaysOnTopWorks = true;
402 }
403 #if OSL_DEBUG_LEVEL > 1
404 fprintf( stderr, " %s%s\n", pAtomNames[i], ((pMatch)&&(pMatch->nProtocol != -1)) ? "" : " (unsupported)" );
405 #endif
406 XFree( pAtomNames[i] );
407 }
408 }
409 XFree( pProperty );
410 pProperty = nullptr;
411 }
412 else if( pProperty )
413 {
414 XFree( pProperty );
415 pProperty = nullptr;
416 }
417
418 // get number of desktops
419 if( m_aWMAtoms[ NET_NUMBER_OF_DESKTOPS ]
420 && XGetWindowProperty( m_pDisplay,
421 m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ),
422 m_aWMAtoms[ NET_NUMBER_OF_DESKTOPS ],
423 0, 1,
424 False,
425 XA_CARDINAL,
426 &aRealType,
427 &nFormat,
428 &nItems,
429 &nBytesLeft,
430 &pProperty ) == 0
431 && pProperty
432 )
433 {
434 m_nDesktops = *reinterpret_cast<long*>(pProperty);
435 XFree( pProperty );
436 pProperty = nullptr;
437 // get work areas
438 if( m_aWMAtoms[ NET_WORKAREA ]
439 && XGetWindowProperty( m_pDisplay,
440 m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ),
441 m_aWMAtoms[ NET_WORKAREA ],
442 0, 4*m_nDesktops,
443 False,
444 XA_CARDINAL,
445 &aRealType,
446 &nFormat,
447 &nItems,
448 &nBytesLeft,
449 &pProperty
450 ) == 0
451 && nItems == 4*static_cast<unsigned>(m_nDesktops)
452 )
453 {
454 m_aWMWorkAreas = ::std::vector< tools::Rectangle > ( m_nDesktops );
455 long* pValues = reinterpret_cast<long*>(pProperty);
456 for( int i = 0; i < m_nDesktops; i++ )
457 {
458 Point aPoint( pValues[4*i],
459 pValues[4*i+1] );
460 Size aSize( pValues[4*i+2],
461 pValues[4*i+3] );
462 tools::Rectangle aWorkArea( aPoint, aSize );
463 m_aWMWorkAreas[i] = aWorkArea;
464 if( aWorkArea != m_aWMWorkAreas[0] )
465 m_bEqualWorkAreas = false;
466 #if OSL_DEBUG_LEVEL > 1
467 fprintf( stderr, "workarea %d: %ldx%ld+%ld+%ld\n",
468 i,
469 m_aWMWorkAreas[i].GetWidth(),
470 m_aWMWorkAreas[i].GetHeight(),
471 m_aWMWorkAreas[i].Left(),
472 m_aWMWorkAreas[i].Top() );
473 #endif
474 }
475 XFree( pProperty );
476 }
477 else
478 {
479 #if OSL_DEBUG_LEVEL > 1
480 fprintf( stderr, "%ld workareas for %d desktops !\n", nItems/4, m_nDesktops );
481 #endif
482 if( pProperty )
483 {
484 XFree(pProperty);
485 pProperty = nullptr;
486 }
487 }
488 }
489 else if( pProperty )
490 {
491 XFree( pProperty );
492 pProperty = nullptr;
493 }
494 }
495 else if( pProperty )
496 {
497 XFree( pProperty );
498 pProperty = nullptr;
499 }
500 }
501
502 /*
503 * GnomeWMAdaptor constructor
504 */
505
GnomeWMAdaptor(SalDisplay * pSalDisplay)506 GnomeWMAdaptor::GnomeWMAdaptor( SalDisplay* pSalDisplay ) :
507 WMAdaptor( pSalDisplay ),
508 m_bValid( false )
509 {
510 // currently all Gnome WMs do transient like expected
511
512 Atom aRealType = None;
513 int nFormat = 8;
514 unsigned long nItems = 0;
515 unsigned long nBytesLeft = 0;
516 unsigned char* pProperty = nullptr;
517
518 initAtoms();
519
520 // check for GnomeWM
521 if( m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ] && m_aWMAtoms[ WIN_PROTOCOLS ] )
522 {
523 ::Window aWMChild = None;
524 if( XGetWindowProperty( m_pDisplay,
525 m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ),
526 m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ],
527 0, 1,
528 False,
529 XA_CARDINAL,
530 &aRealType,
531 &nFormat,
532 &nItems,
533 &nBytesLeft,
534 &pProperty ) == 0
535 && aRealType == XA_CARDINAL
536 && nFormat == 32
537 && nItems != 0
538 )
539 {
540 aWMChild = *reinterpret_cast< ::Window* >(pProperty);
541 XFree( pProperty );
542 pProperty = nullptr;
543 ::Window aCheckWindow = None;
544 GetGenericUnixSalData()->ErrorTrapPush();
545 if( XGetWindowProperty( m_pDisplay,
546 aWMChild,
547 m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ],
548 0, 1,
549 False,
550 XA_CARDINAL,
551 &aRealType,
552 &nFormat,
553 &nItems,
554 &nBytesLeft,
555 &pProperty ) == 0
556 && aRealType == XA_CARDINAL
557 && nFormat == 32
558 && nItems != 0 )
559 {
560 if (! GetGenericUnixSalData()->ErrorTrapPop( false ) )
561 {
562 GetGenericUnixSalData()->ErrorTrapPush();
563
564 aCheckWindow = *reinterpret_cast< ::Window* >(pProperty);
565 XFree( pProperty );
566 pProperty = nullptr;
567 if( aCheckWindow == aWMChild )
568 {
569 m_bValid = true;
570 /*
571 * get name of WM
572 * this is NOT part of the GNOME WM hints, but e.g. Sawfish
573 * already supports this part of the extended WM hints
574 */
575 m_aWMAtoms[ UTF8_STRING ] = XInternAtom( m_pDisplay, "UTF8_STRING", False );
576 getNetWmName();
577 }
578 }
579 else
580 GetGenericUnixSalData()->ErrorTrapPush();
581 }
582 GetGenericUnixSalData()->ErrorTrapPop();
583 }
584 else if( pProperty )
585 {
586 XFree( pProperty );
587 pProperty = nullptr;
588 }
589 }
590 if( m_bValid
591 && XGetWindowProperty( m_pDisplay,
592 m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ),
593 m_aWMAtoms[ WIN_PROTOCOLS ],
594 0, 0,
595 False,
596 XA_ATOM,
597 &aRealType,
598 &nFormat,
599 &nItems,
600 &nBytesLeft,
601 &pProperty ) == 0
602 && aRealType == XA_ATOM
603 && nFormat == 32
604 )
605 {
606 if( pProperty )
607 {
608 XFree( pProperty );
609 pProperty = nullptr;
610 }
611 // collect supported protocols
612 if( XGetWindowProperty( m_pDisplay,
613 m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ),
614 m_aWMAtoms[ WIN_PROTOCOLS ],
615 0, nBytesLeft/4,
616 False,
617 XA_ATOM,
618 &aRealType,
619 &nFormat,
620 &nItems,
621 &nBytesLeft,
622 &pProperty ) == 0
623 && pProperty
624 )
625 {
626 Atom* pAtoms = reinterpret_cast<Atom*>(pProperty);
627 char** pAtomNames = static_cast<char**>(alloca( sizeof(char*)*nItems ));
628 if( XGetAtomNames( m_pDisplay, pAtoms, nItems, pAtomNames ) )
629 {
630 #if OSL_DEBUG_LEVEL > 1
631 fprintf( stderr, "supported protocols:\n" );
632 #endif
633 for( unsigned long i = 0; i < nItems; i++ )
634 {
635 // #i80971# protect against invalid atoms
636 if( pAtomNames[i] == nullptr )
637 continue;
638
639 WMAdaptorProtocol aSearch;
640 aSearch.pProtocol = pAtomNames[i];
641 WMAdaptorProtocol* pMatch = static_cast<WMAdaptorProtocol*>(
642 bsearch( &aSearch,
643 aProtocolTab,
644 SAL_N_ELEMENTS( aProtocolTab ),
645 sizeof( struct WMAdaptorProtocol ),
646 compareProtocol ));
647 if( pMatch )
648 {
649 m_aWMAtoms[ pMatch->nProtocol ] = pAtoms[ i ];
650 if( pMatch->nProtocol == WIN_LAYER )
651 m_bEnableAlwaysOnTopWorks = true;
652 }
653 if( strncmp( "_ICEWM_TRAY", pAtomNames[i], 11 ) == 0 )
654 {
655 m_aWMName = "IceWM";
656 m_nWinGravity = NorthWestGravity;
657 m_nInitWinGravity = NorthWestGravity;
658 }
659 #if OSL_DEBUG_LEVEL > 1
660 fprintf( stderr, " %s%s\n", pAtomNames[i], ((pMatch) && (pMatch->nProtocol != -1)) ? "" : " (unsupported)" );
661 #endif
662 XFree( pAtomNames[i] );
663 }
664 }
665 XFree( pProperty );
666 pProperty = nullptr;
667 }
668 else if( pProperty )
669 {
670 XFree( pProperty );
671 pProperty = nullptr;
672 }
673
674 // get number of desktops
675 if( m_aWMAtoms[ WIN_WORKSPACE_COUNT ]
676 && XGetWindowProperty( m_pDisplay,
677 m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ),
678 m_aWMAtoms[ WIN_WORKSPACE_COUNT ],
679 0, 1,
680 False,
681 XA_CARDINAL,
682 &aRealType,
683 &nFormat,
684 &nItems,
685 &nBytesLeft,
686 &pProperty ) == 0
687 && pProperty
688 )
689 {
690 m_nDesktops = *reinterpret_cast<long*>(pProperty);
691 XFree( pProperty );
692 pProperty = nullptr;
693 }
694 else if( pProperty )
695 {
696 XFree( pProperty );
697 pProperty = nullptr;
698 }
699 }
700 else if( pProperty )
701 {
702 XFree( pProperty );
703 pProperty = nullptr;
704 }
705 }
706
707 /*
708 * getNetWmName()
709 */
getNetWmName()710 bool WMAdaptor::getNetWmName()
711 {
712 Atom aRealType = None;
713 int nFormat = 8;
714 unsigned long nItems = 0;
715 unsigned long nBytesLeft = 0;
716 unsigned char* pProperty = nullptr;
717 bool bNetWM = false;
718
719 if( m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ] && m_aWMAtoms[ NET_WM_NAME ] )
720 {
721 ::Window aWMChild = None;
722 if( XGetWindowProperty( m_pDisplay,
723 m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ),
724 m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ],
725 0, 1,
726 False,
727 XA_WINDOW,
728 &aRealType,
729 &nFormat,
730 &nItems,
731 &nBytesLeft,
732 &pProperty ) == 0
733 && aRealType == XA_WINDOW
734 && nFormat == 32
735 && nItems != 0
736 )
737 {
738 aWMChild = *reinterpret_cast< ::Window* >(pProperty);
739 XFree( pProperty );
740 pProperty = nullptr;
741 ::Window aCheckWindow = None;
742 GetGenericUnixSalData()->ErrorTrapPush();
743 if( XGetWindowProperty( m_pDisplay,
744 aWMChild,
745 m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ],
746 0, 1,
747 False,
748 XA_WINDOW,
749 &aRealType,
750 &nFormat,
751 &nItems,
752 &nBytesLeft,
753 &pProperty ) == 0
754 && aRealType == XA_WINDOW
755 && nFormat == 32
756 && nItems != 0 )
757 {
758 if ( ! GetGenericUnixSalData()->ErrorTrapPop( false ) )
759 {
760 GetGenericUnixSalData()->ErrorTrapPush();
761 aCheckWindow = *reinterpret_cast< ::Window* >(pProperty);
762 XFree( pProperty );
763 pProperty = nullptr;
764 if( aCheckWindow == aWMChild )
765 {
766 bNetWM = true;
767 // get name of WM
768 m_aWMAtoms[ UTF8_STRING ] = XInternAtom( m_pDisplay, "UTF8_STRING", False );
769 if( XGetWindowProperty( m_pDisplay,
770 aWMChild,
771 m_aWMAtoms[ NET_WM_NAME ],
772 0, 256,
773 False,
774 AnyPropertyType, /* m_aWMAtoms[ UTF8_STRING ],*/
775 &aRealType,
776 &nFormat,
777 &nItems,
778 &nBytesLeft,
779 &pProperty ) == 0
780 && nItems != 0
781 )
782 {
783 if (aRealType == m_aWMAtoms[ UTF8_STRING ])
784 m_aWMName = OUString( reinterpret_cast<char*>(pProperty), nItems, RTL_TEXTENCODING_UTF8 );
785 else if (aRealType == XA_STRING)
786 m_aWMName = OUString( reinterpret_cast<char*>(pProperty), nItems, RTL_TEXTENCODING_ISO_8859_1 );
787
788 XFree( pProperty );
789 pProperty = nullptr;
790 }
791 else if( pProperty )
792 {
793 XFree( pProperty );
794 pProperty = nullptr;
795 }
796
797 // if this is metacity, check for version to enable a legacy workaround
798 if( m_aWMName == "Metacity" )
799 {
800 int nVersionMajor = 0, nVersionMinor = 0;
801 Atom nVersionAtom = XInternAtom( m_pDisplay, "_METACITY_VERSION", True );
802 if( nVersionAtom )
803 {
804 if( XGetWindowProperty( m_pDisplay,
805 aWMChild,
806 nVersionAtom,
807 0, 256,
808 False,
809 m_aWMAtoms[ UTF8_STRING ],
810 &aRealType,
811 &nFormat,
812 &nItems,
813 &nBytesLeft,
814 &pProperty ) == 0
815 && nItems != 0
816 )
817 {
818 OUString aMetaVersion( reinterpret_cast<char*>(pProperty), nItems, RTL_TEXTENCODING_UTF8 );
819 sal_Int32 nIdx {0};
820 nVersionMajor = aMetaVersion.getToken(0, '.', nIdx).toInt32();
821 nVersionMinor = aMetaVersion.getToken(0, '.', nIdx).toInt32();
822 }
823 if( pProperty )
824 {
825 XFree( pProperty );
826 pProperty = nullptr;
827 }
828 }
829 if( nVersionMajor < 2 || (nVersionMajor == 2 && nVersionMinor < 12) )
830 m_bLegacyPartialFullscreen = true;
831 }
832 }
833 }
834 else
835 {
836 if( pProperty )
837 {
838 XFree( pProperty );
839 pProperty = nullptr;
840 }
841 GetGenericUnixSalData()->ErrorTrapPush();
842 }
843 }
844
845 GetGenericUnixSalData()->ErrorTrapPop();
846 }
847 else if( pProperty )
848 {
849 XFree( pProperty );
850 pProperty = nullptr;
851 }
852 }
853 return bNetWM;
854 }
855
getWMshouldSwitchWorkspace() const856 bool WMAdaptor::getWMshouldSwitchWorkspace() const
857 {
858 if( ! m_bWMshouldSwitchWorkspaceInit )
859 {
860 WMAdaptor * pWMA = const_cast<WMAdaptor*>(this);
861
862 pWMA->m_bWMshouldSwitchWorkspace = true;
863 vcl::SettingsConfigItem* pItem = vcl::SettingsConfigItem::get();
864 OUString aSetting( pItem->getValue( "WM",
865 "ShouldSwitchWorkspace" ) );
866 if( aSetting.isEmpty() )
867 {
868 if( m_aWMName == "awesome" )
869 {
870 pWMA->m_bWMshouldSwitchWorkspace = false;
871 }
872 }
873 else
874 pWMA->m_bWMshouldSwitchWorkspace = aSetting.toBoolean();
875 pWMA->m_bWMshouldSwitchWorkspaceInit = true;
876 }
877 return m_bWMshouldSwitchWorkspace;
878 }
879
880 /*
881 * WMAdaptor::isValid()
882 */
isValid() const883 bool WMAdaptor::isValid() const
884 {
885 return true;
886 }
887
888 /*
889 * NetWMAdaptor::isValid()
890 */
isValid() const891 bool NetWMAdaptor::isValid() const
892 {
893 // some necessary sanity checks; there are WMs out there
894 // which implement some of the WM hints spec without
895 // real functionality
896 return
897 m_aWMAtoms[ NET_SUPPORTED ]
898 && m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ]
899 && m_aWMAtoms[ NET_WM_NAME ]
900 && m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL ]
901 && m_aWMAtoms[ NET_WM_WINDOW_TYPE_DIALOG ]
902 ;
903 }
904
905 /*
906 * GnomeWMAdaptor::isValid()
907 */
isValid() const908 bool GnomeWMAdaptor::isValid() const
909 {
910 return m_bValid;
911 }
912
913 /*
914 * WMAdaptor::initAtoms
915 */
916
initAtoms()917 void WMAdaptor::initAtoms()
918 {
919 // get basic atoms
920 for(const WMAdaptorProtocol & i : aAtomTab)
921 m_aWMAtoms[ i.nProtocol ] = XInternAtom( m_pDisplay, i.pProtocol, False );
922 m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ] = XInternAtom( m_pDisplay, "_NET_SUPPORTING_WM_CHECK", True );
923 m_aWMAtoms[ NET_WM_NAME ] = XInternAtom( m_pDisplay, "_NET_WM_NAME", True );
924 }
925
926 /*
927 * NetWMAdaptor::initAtoms
928 */
929
initAtoms()930 void NetWMAdaptor::initAtoms()
931 {
932 WMAdaptor::initAtoms();
933
934 m_aWMAtoms[ NET_SUPPORTED ] = XInternAtom( m_pDisplay, "_NET_SUPPORTED", True );
935 }
936
937 /*
938 * GnomeWMAdaptor::initAtoms
939 */
940
initAtoms()941 void GnomeWMAdaptor::initAtoms()
942 {
943 WMAdaptor::initAtoms();
944
945 m_aWMAtoms[ WIN_PROTOCOLS ] = XInternAtom( m_pDisplay, "_WIN_PROTOCOLS", True );
946 m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ] = XInternAtom( m_pDisplay, "_WIN_SUPPORTING_WM_CHECK", True );
947 }
948
949 /*
950 * WMAdaptor::setWMName
951 * sets WM_NAME
952 * WM_ICON_NAME
953 */
954
setWMName(X11SalFrame * pFrame,const OUString & rWMName) const955 void WMAdaptor::setWMName( X11SalFrame* pFrame, const OUString& rWMName ) const
956 {
957 OString aTitle(OUStringToOString(rWMName,
958 osl_getThreadTextEncoding()));
959
960 OString aWMLocale;
961 rtl_Locale* pLocale = nullptr;
962 osl_getProcessLocale( &pLocale );
963 if( pLocale )
964 {
965 OUString aLocaleString( LanguageTag( *pLocale).getGlibcLocaleString( OUString()));
966 aWMLocale = OUStringToOString( aLocaleString, RTL_TEXTENCODING_ISO_8859_1 );
967 }
968 else
969 {
970 static const char* pLang = getenv( "LANG" );
971 aWMLocale = pLang ? pLang : "C";
972 }
973
974 char* pT = const_cast<char*>(aTitle.getStr());
975 XTextProperty aProp = { nullptr, None, 0, 0 };
976 XmbTextListToTextProperty( m_pDisplay,
977 &pT,
978 1,
979 XStdICCTextStyle,
980 &aProp );
981
982 unsigned char const * pData = aProp.nitems ? aProp.value : reinterpret_cast<unsigned char const *>(aTitle.getStr());
983 Atom nType = aProp.nitems ? aProp.encoding : XA_STRING;
984 int nFormat = aProp.nitems ? aProp.format : 8;
985 int nBytes = aProp.nitems ? aProp.nitems : aTitle.getLength();
986 const SystemEnvData* pEnv = pFrame->GetSystemData();
987 XChangeProperty( m_pDisplay,
988 static_cast<::Window>(pEnv->aShellWindow),
989 XA_WM_NAME,
990 nType,
991 nFormat,
992 PropModeReplace,
993 pData,
994 nBytes );
995 XChangeProperty( m_pDisplay,
996 static_cast<::Window>(pEnv->aShellWindow),
997 XA_WM_ICON_NAME,
998 nType,
999 nFormat,
1000 PropModeReplace,
1001 pData,
1002 nBytes );
1003 XChangeProperty( m_pDisplay,
1004 static_cast<::Window>(pEnv->aShellWindow),
1005 m_aWMAtoms[ WM_LOCALE_NAME ],
1006 XA_STRING,
1007 8,
1008 PropModeReplace,
1009 reinterpret_cast<unsigned char const *>(aWMLocale.getStr()),
1010 aWMLocale.getLength() );
1011 if (aProp.value != nullptr)
1012 XFree( aProp.value );
1013 }
1014
1015 /*
1016 * NetWMAdaptor::setWMName
1017 * sets WM_NAME
1018 * _NET_WM_NAME
1019 * WM_ICON_NAME
1020 * _NET_WM_ICON_NAME
1021 */
setWMName(X11SalFrame * pFrame,const OUString & rWMName) const1022 void NetWMAdaptor::setWMName( X11SalFrame* pFrame, const OUString& rWMName ) const
1023 {
1024 WMAdaptor::setWMName( pFrame, rWMName );
1025
1026 OString aTitle(OUStringToOString(rWMName, RTL_TEXTENCODING_UTF8));
1027 const SystemEnvData* pEnv = pFrame->GetSystemData();
1028 if( m_aWMAtoms[ NET_WM_NAME ] )
1029 XChangeProperty( m_pDisplay,
1030 static_cast<::Window>(pEnv->aShellWindow),
1031 m_aWMAtoms[ NET_WM_NAME ],
1032 m_aWMAtoms[ UTF8_STRING ],
1033 8,
1034 PropModeReplace,
1035 reinterpret_cast<unsigned char const *>(aTitle.getStr()),
1036 aTitle.getLength() );
1037 if( m_aWMAtoms[ NET_WM_ICON_NAME ] )
1038 XChangeProperty( m_pDisplay,
1039 static_cast<::Window>(pEnv->aShellWindow),
1040 m_aWMAtoms[ NET_WM_ICON_NAME ],
1041 m_aWMAtoms[ UTF8_STRING ],
1042 8,
1043 PropModeReplace,
1044 reinterpret_cast<unsigned char const *>(aTitle.getStr()),
1045 aTitle.getLength() );
1046 }
1047
1048 /*
1049 * NetWMAdaptor::setNetWMState
1050 * sets _NET_WM_STATE
1051 */
setNetWMState(X11SalFrame * pFrame) const1052 void NetWMAdaptor::setNetWMState( X11SalFrame* pFrame ) const
1053 {
1054 if( m_aWMAtoms[ NET_WM_STATE ] )
1055 {
1056 Atom aStateAtoms[ 10 ];
1057 int nStateAtoms = 0;
1058
1059 // set NET_WM_STATE_MODAL
1060 if( pFrame->mbMaximizedVert
1061 && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] )
1062 aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ];
1063 if( pFrame->mbMaximizedHorz
1064 && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ] )
1065 aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ];
1066 if( pFrame->bAlwaysOnTop_ && m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ] )
1067 aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ];
1068 if( pFrame->mbShaded && m_aWMAtoms[ NET_WM_STATE_SHADED ] )
1069 aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_SHADED ];
1070 if( pFrame->mbFullScreen && m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ] )
1071 aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ];
1072 if( pFrame->meWindowType == WMWindowType::Utility && m_aWMAtoms[ NET_WM_STATE_SKIP_TASKBAR ] )
1073 aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_SKIP_TASKBAR ];
1074
1075 if( nStateAtoms )
1076 {
1077 XChangeProperty( m_pDisplay,
1078 pFrame->GetShellWindow(),
1079 m_aWMAtoms[ NET_WM_STATE ],
1080 XA_ATOM,
1081 32,
1082 PropModeReplace,
1083 reinterpret_cast<unsigned char*>(aStateAtoms),
1084 nStateAtoms
1085 );
1086 }
1087 else
1088 XDeleteProperty( m_pDisplay,
1089 pFrame->GetShellWindow(),
1090 m_aWMAtoms[ NET_WM_STATE ] );
1091 if( pFrame->mbMaximizedHorz
1092 && pFrame->mbMaximizedVert
1093 && ! ( pFrame->nStyle_ & SalFrameStyleFlags::SIZEABLE ) )
1094 {
1095 /*
1096 * for maximizing use NorthWestGravity (including decoration)
1097 */
1098 XSizeHints hints;
1099 long supplied;
1100 bool bHint = false;
1101 if( XGetWMNormalHints( m_pDisplay,
1102 pFrame->GetShellWindow(),
1103 &hints,
1104 &supplied ) )
1105 {
1106 bHint = true;
1107 hints.flags |= PWinGravity;
1108 hints.win_gravity = NorthWestGravity;
1109 XSetWMNormalHints( m_pDisplay,
1110 pFrame->GetShellWindow(),
1111 &hints );
1112 XSync( m_pDisplay, False );
1113 }
1114
1115 // SetPosSize necessary to set width/height, min/max w/h
1116 sal_Int32 nCurrent = 0;
1117 /*
1118 * get current desktop here if work areas have different size
1119 * (does this happen on any platform ?)
1120 */
1121 if( ! m_bEqualWorkAreas )
1122 {
1123 nCurrent = getCurrentWorkArea();
1124 if( nCurrent < 0 )
1125 nCurrent = 0;
1126 }
1127 tools::Rectangle aPosSize = m_aWMWorkAreas[nCurrent];
1128 const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
1129 aPosSize = tools::Rectangle( Point( aPosSize.Left() + rGeom.nLeftDecoration,
1130 aPosSize.Top() + rGeom.nTopDecoration ),
1131 Size( aPosSize.GetWidth()
1132 - rGeom.nLeftDecoration
1133 - rGeom.nRightDecoration,
1134 aPosSize.GetHeight()
1135 - rGeom.nTopDecoration
1136 - rGeom.nBottomDecoration )
1137 );
1138 pFrame->SetPosSize( aPosSize );
1139
1140 /*
1141 * reset gravity hint to static gravity
1142 * (this should not move window according to ICCCM)
1143 */
1144 if( bHint && pFrame->nShowState_ != SHOWSTATE_UNKNOWN )
1145 {
1146 hints.win_gravity = StaticGravity;
1147 XSetWMNormalHints( m_pDisplay,
1148 pFrame->GetShellWindow(),
1149 &hints );
1150 }
1151 }
1152 }
1153 }
1154
1155 /*
1156 * GnomeWMAdaptor::setNetWMState
1157 * sets _WIN_STATE
1158 */
setGnomeWMState(X11SalFrame * pFrame) const1159 void GnomeWMAdaptor::setGnomeWMState( X11SalFrame* pFrame ) const
1160 {
1161 if( m_aWMAtoms[ WIN_STATE ] )
1162 {
1163 sal_uInt32 nWinWMState = 0;
1164
1165 if( pFrame->mbMaximizedVert )
1166 nWinWMState |= 1 << 2;
1167 if( pFrame->mbMaximizedHorz )
1168 nWinWMState |= 1 << 3;
1169 if( pFrame->mbShaded )
1170 nWinWMState |= 1 << 5;
1171
1172 XChangeProperty( m_pDisplay,
1173 pFrame->GetShellWindow(),
1174 m_aWMAtoms[ WIN_STATE ],
1175 XA_CARDINAL,
1176 32,
1177 PropModeReplace,
1178 reinterpret_cast<unsigned char*>(&nWinWMState),
1179 1
1180 );
1181 if( pFrame->mbMaximizedHorz
1182 && pFrame->mbMaximizedVert
1183 && ! ( pFrame->nStyle_ & SalFrameStyleFlags::SIZEABLE ) )
1184 {
1185 /*
1186 * for maximizing use NorthWestGravity (including decoration)
1187 */
1188 XSizeHints hints;
1189 long supplied;
1190 bool bHint = false;
1191 if( XGetWMNormalHints( m_pDisplay,
1192 pFrame->GetShellWindow(),
1193 &hints,
1194 &supplied ) )
1195 {
1196 bHint = true;
1197 hints.flags |= PWinGravity;
1198 hints.win_gravity = NorthWestGravity;
1199 XSetWMNormalHints( m_pDisplay,
1200 pFrame->GetShellWindow(),
1201 &hints );
1202 XSync( m_pDisplay, False );
1203 }
1204
1205 // SetPosSize necessary to set width/height, min/max w/h
1206 sal_Int32 nCurrent = 0;
1207 /*
1208 * get current desktop here if work areas have different size
1209 * (does this happen on any platform ?)
1210 */
1211 if( ! m_bEqualWorkAreas )
1212 {
1213 nCurrent = getCurrentWorkArea();
1214 if( nCurrent < 0 )
1215 nCurrent = 0;
1216 }
1217 tools::Rectangle aPosSize = m_aWMWorkAreas[nCurrent];
1218 const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
1219 aPosSize = tools::Rectangle( Point( aPosSize.Left() + rGeom.nLeftDecoration,
1220 aPosSize.Top() + rGeom.nTopDecoration ),
1221 Size( aPosSize.GetWidth()
1222 - rGeom.nLeftDecoration
1223 - rGeom.nRightDecoration,
1224 aPosSize.GetHeight()
1225 - rGeom.nTopDecoration
1226 - rGeom.nBottomDecoration )
1227 );
1228 pFrame->SetPosSize( aPosSize );
1229
1230 /*
1231 * reset gravity hint to static gravity
1232 * (this should not move window according to ICCCM)
1233 */
1234 if( bHint && pFrame->nShowState_ != SHOWSTATE_UNKNOWN )
1235 {
1236 hints.win_gravity = StaticGravity;
1237 XSetWMNormalHints( m_pDisplay,
1238 pFrame->GetShellWindow(),
1239 &hints );
1240 }
1241 }
1242 }
1243 }
1244
1245 /*
1246 * WMAdaptor::setFrameDecoration
1247 * sets _MOTIF_WM_HINTS
1248 * WM_TRANSIENT_FOR
1249 */
1250
setFrameTypeAndDecoration(X11SalFrame * pFrame,WMWindowType eType,int nDecorationFlags,X11SalFrame * pReferenceFrame) const1251 void WMAdaptor::setFrameTypeAndDecoration( X11SalFrame* pFrame, WMWindowType eType, int nDecorationFlags, X11SalFrame* pReferenceFrame ) const
1252 {
1253 pFrame->meWindowType = eType;
1254
1255 if( ! pFrame->mbFullScreen )
1256 {
1257 // set mwm hints
1258 struct _mwmhints {
1259 unsigned long flags, func, deco;
1260 long input_mode;
1261 unsigned long status;
1262 } aHint;
1263
1264 aHint.flags = 15; /* flags for functions, decoration, input mode and status */
1265 aHint.deco = 0;
1266 aHint.func = 1 << 2;
1267 aHint.status = 0;
1268 aHint.input_mode = 0;
1269
1270 // evaluate decoration flags
1271 if( nDecorationFlags & decoration_All )
1272 {
1273 aHint.deco = 1;
1274 aHint.func = 1;
1275 }
1276 else
1277 {
1278 if( nDecorationFlags & decoration_Title )
1279 aHint.deco |= 1 << 3;
1280 if( nDecorationFlags & decoration_Border )
1281 aHint.deco |= 1 << 1;
1282 if( nDecorationFlags & decoration_Resize )
1283 {
1284 aHint.deco |= 1 << 2;
1285 aHint.func |= 1 << 1;
1286 }
1287 if( nDecorationFlags & decoration_MinimizeBtn )
1288 {
1289 aHint.deco |= 1 << 5;
1290 aHint.func |= 1 << 3;
1291 }
1292 if( nDecorationFlags & decoration_MaximizeBtn )
1293 {
1294 aHint.deco |= 1 << 6;
1295 aHint.func |= 1 << 4;
1296 }
1297 if( nDecorationFlags & decoration_CloseBtn )
1298 {
1299 aHint.deco |= 1 << 4;
1300 aHint.func |= 1 << 5;
1301 }
1302 }
1303
1304 // set the hint
1305 XChangeProperty( m_pDisplay,
1306 pFrame->GetShellWindow(),
1307 m_aWMAtoms[ MOTIF_WM_HINTS ],
1308 m_aWMAtoms[ MOTIF_WM_HINTS ],
1309 32,
1310 PropModeReplace,
1311 reinterpret_cast<unsigned char*>(&aHint),
1312 5 );
1313 }
1314
1315 // set transientFor hint
1316 /* #91030# dtwm will not map a dialogue if the transient
1317 * window is iconified. This is deemed undesirable because
1318 * message boxes do not get mapped, so use the root as transient
1319 * instead.
1320 */
1321 if( pReferenceFrame )
1322 {
1323 XSetTransientForHint( m_pDisplay,
1324 pFrame->GetShellWindow(),
1325 pReferenceFrame->bMapped_ ?
1326 pReferenceFrame->GetShellWindow() :
1327 m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() )
1328 );
1329 if( ! pReferenceFrame->bMapped_ )
1330 pFrame->mbTransientForRoot = true;
1331 }
1332 }
1333
1334 /*
1335 * NetWMAdaptor::setFrameDecoration
1336 * sets _MOTIF_WM_HINTS
1337 * _NET_WM_WINDOW_TYPE
1338 * _NET_WM_STATE
1339 * WM_TRANSIENT_FOR
1340 */
1341
setFrameTypeAndDecoration(X11SalFrame * pFrame,WMWindowType eType,int nDecorationFlags,X11SalFrame * pReferenceFrame) const1342 void NetWMAdaptor::setFrameTypeAndDecoration( X11SalFrame* pFrame, WMWindowType eType, int nDecorationFlags, X11SalFrame* pReferenceFrame ) const
1343 {
1344 WMAdaptor::setFrameTypeAndDecoration( pFrame, eType, nDecorationFlags, pReferenceFrame );
1345
1346 setNetWMState( pFrame );
1347
1348 // set NET_WM_WINDOW_TYPE
1349 if( m_aWMAtoms[ NET_WM_WINDOW_TYPE ] )
1350 {
1351 Atom aWindowTypes[4];
1352 int nWindowTypes = 0;
1353 switch( eType )
1354 {
1355 case WMWindowType::Utility:
1356 aWindowTypes[nWindowTypes++] =
1357 m_aWMAtoms[ NET_WM_WINDOW_TYPE_UTILITY ] ?
1358 m_aWMAtoms[ NET_WM_WINDOW_TYPE_UTILITY ] :
1359 m_aWMAtoms[ NET_WM_WINDOW_TYPE_DIALOG ];
1360 break;
1361 case WMWindowType::ModelessDialogue:
1362 aWindowTypes[nWindowTypes++] =
1363 m_aWMAtoms[ NET_WM_WINDOW_TYPE_DIALOG ];
1364 break;
1365 case WMWindowType::Splash:
1366 aWindowTypes[nWindowTypes++] =
1367 m_aWMAtoms[ NET_WM_WINDOW_TYPE_SPLASH ] ?
1368 m_aWMAtoms[ NET_WM_WINDOW_TYPE_SPLASH ] :
1369 m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL ];
1370 break;
1371 case WMWindowType::Toolbar:
1372 if( m_aWMAtoms[ KDE_NET_WM_WINDOW_TYPE_OVERRIDE ] )
1373 aWindowTypes[nWindowTypes++] = m_aWMAtoms[ KDE_NET_WM_WINDOW_TYPE_OVERRIDE ];
1374 aWindowTypes[nWindowTypes++] =
1375 m_aWMAtoms[ NET_WM_WINDOW_TYPE_TOOLBAR ] ?
1376 m_aWMAtoms[ NET_WM_WINDOW_TYPE_TOOLBAR ] :
1377 m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL];
1378 break;
1379 case WMWindowType::Dock:
1380 aWindowTypes[nWindowTypes++] =
1381 m_aWMAtoms[ NET_WM_WINDOW_TYPE_DOCK ] ?
1382 m_aWMAtoms[ NET_WM_WINDOW_TYPE_DOCK ] :
1383 m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL];
1384 break;
1385 default:
1386 aWindowTypes[nWindowTypes++] = m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL ];
1387 break;
1388 }
1389 XChangeProperty( m_pDisplay,
1390 pFrame->GetShellWindow(),
1391 m_aWMAtoms[ NET_WM_WINDOW_TYPE ],
1392 XA_ATOM,
1393 32,
1394 PropModeReplace,
1395 reinterpret_cast<unsigned char*>(aWindowTypes),
1396 nWindowTypes );
1397 }
1398 if( ( eType == WMWindowType::ModelessDialogue )
1399 && ! pReferenceFrame )
1400 {
1401 XSetTransientForHint( m_pDisplay,
1402 pFrame->GetShellWindow(),
1403 m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ) );
1404 pFrame->mbTransientForRoot = true;
1405 }
1406 }
1407
1408 /*
1409 * WMAdaptor::maximizeFrame
1410 */
1411
maximizeFrame(X11SalFrame * pFrame,bool bHorizontal,bool bVertical) const1412 void WMAdaptor::maximizeFrame( X11SalFrame* pFrame, bool bHorizontal, bool bVertical ) const
1413 {
1414 pFrame->mbMaximizedVert = bVertical;
1415 pFrame->mbMaximizedHorz = bHorizontal;
1416
1417 const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
1418
1419 // discard pending configure notifies for this frame
1420 XSync( m_pDisplay, False );
1421 XEvent aDiscard;
1422 while( XCheckTypedWindowEvent( m_pDisplay,
1423 pFrame->GetShellWindow(),
1424 ConfigureNotify,
1425 &aDiscard ) )
1426 ;
1427 while( XCheckTypedWindowEvent( m_pDisplay,
1428 pFrame->GetWindow(),
1429 ConfigureNotify,
1430 &aDiscard ) )
1431 ;
1432
1433 if( bHorizontal || bVertical )
1434 {
1435 Size aScreenSize( m_pSalDisplay->GetScreenSize( pFrame->GetScreenNumber() ) );
1436 Point aTL( rGeom.nLeftDecoration, rGeom.nTopDecoration );
1437 if( m_pSalDisplay->IsXinerama() )
1438 {
1439 Point aMed( aTL.X() + rGeom.nWidth/2, aTL.Y() + rGeom.nHeight/2 );
1440 const std::vector< tools::Rectangle >& rScreens = m_pSalDisplay->GetXineramaScreens();
1441 for(const auto & rScreen : rScreens)
1442 if( rScreen.IsInside( aMed ) )
1443 {
1444 aTL += rScreen.TopLeft();
1445 aScreenSize = rScreen.GetSize();
1446 break;
1447 }
1448 }
1449 tools::Rectangle aTarget( aTL,
1450 Size( aScreenSize.Width() - rGeom.nLeftDecoration - rGeom.nTopDecoration,
1451 aScreenSize.Height() - rGeom.nTopDecoration - rGeom.nBottomDecoration )
1452 );
1453 if( ! bHorizontal )
1454 {
1455 aTarget.SetSize(
1456 Size(
1457 pFrame->maRestorePosSize.IsEmpty() ?
1458 rGeom.nWidth : pFrame->maRestorePosSize.GetWidth(),
1459 aTarget.GetHeight()
1460 )
1461 );
1462 aTarget.SetLeft(
1463 pFrame->maRestorePosSize.IsEmpty() ?
1464 rGeom.nX : pFrame->maRestorePosSize.Left() );
1465 }
1466 else if( ! bVertical )
1467 {
1468 aTarget.SetSize(
1469 Size(
1470 aTarget.GetWidth(),
1471 pFrame->maRestorePosSize.IsEmpty() ?
1472 rGeom.nHeight : pFrame->maRestorePosSize.GetHeight()
1473 )
1474 );
1475 aTarget.SetTop(
1476 pFrame->maRestorePosSize.IsEmpty() ?
1477 rGeom.nY : pFrame->maRestorePosSize.Top() );
1478 }
1479
1480 tools::Rectangle aRestore( Point( rGeom.nX, rGeom.nY ), Size( rGeom.nWidth, rGeom.nHeight ) );
1481 if( pFrame->bMapped_ )
1482 {
1483 XSetInputFocus( m_pDisplay,
1484 pFrame->GetShellWindow(),
1485 RevertToNone,
1486 CurrentTime
1487 );
1488 }
1489
1490 if( pFrame->maRestorePosSize.IsEmpty() )
1491 pFrame->maRestorePosSize = aRestore;
1492
1493 pFrame->SetPosSize( aTarget );
1494 pFrame->nWidth_ = aTarget.GetWidth();
1495 pFrame->nHeight_ = aTarget.GetHeight();
1496 XRaiseWindow( m_pDisplay,
1497 pFrame->GetShellWindow()
1498 );
1499 if( pFrame->GetStackingWindow() )
1500 XRaiseWindow( m_pDisplay,
1501 pFrame->GetStackingWindow()
1502 );
1503
1504 }
1505 else
1506 {
1507 pFrame->SetPosSize( pFrame->maRestorePosSize );
1508 pFrame->maRestorePosSize = tools::Rectangle();
1509 pFrame->nWidth_ = rGeom.nWidth;
1510 pFrame->nHeight_ = rGeom.nHeight;
1511 }
1512 }
1513
1514 /*
1515 * NetWMAdaptor::maximizeFrame
1516 * changes _NET_WM_STATE by sending a client message
1517 */
1518
maximizeFrame(X11SalFrame * pFrame,bool bHorizontal,bool bVertical) const1519 void NetWMAdaptor::maximizeFrame( X11SalFrame* pFrame, bool bHorizontal, bool bVertical ) const
1520 {
1521 pFrame->mbMaximizedVert = bVertical;
1522 pFrame->mbMaximizedHorz = bHorizontal;
1523
1524 if( m_aWMAtoms[ NET_WM_STATE ]
1525 && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ]
1526 && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ]
1527 && ( pFrame->nStyle_ & ~SalFrameStyleFlags::DEFAULT )
1528 )
1529 {
1530 if( pFrame->bMapped_ )
1531 {
1532 // window already mapped, send WM a message
1533 XEvent aEvent;
1534 aEvent.type = ClientMessage;
1535 aEvent.xclient.display = m_pDisplay;
1536 aEvent.xclient.window = pFrame->GetShellWindow();
1537 aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ];
1538 aEvent.xclient.format = 32;
1539 aEvent.xclient.data.l[0] = bHorizontal ? 1 : 0;
1540 aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ];
1541 aEvent.xclient.data.l[2] = bHorizontal == bVertical ? m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] : 0;
1542 aEvent.xclient.data.l[3] = 0;
1543 aEvent.xclient.data.l[4] = 0;
1544 XSendEvent( m_pDisplay,
1545 m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
1546 False,
1547 SubstructureNotifyMask | SubstructureRedirectMask,
1548 &aEvent
1549 );
1550 if( bHorizontal != bVertical )
1551 {
1552 aEvent.xclient.data.l[0]= bVertical ? 1 : 0;
1553 aEvent.xclient.data.l[1]= m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ];
1554 aEvent.xclient.data.l[2]= 0;
1555 XSendEvent( m_pDisplay,
1556 m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
1557 False,
1558 SubstructureNotifyMask | SubstructureRedirectMask,
1559 &aEvent
1560 );
1561 }
1562 }
1563 else
1564 {
1565 // window not mapped yet, set _NET_WM_STATE directly
1566 setNetWMState( pFrame );
1567 }
1568 if( !bHorizontal && !bVertical )
1569 pFrame->maRestorePosSize = tools::Rectangle();
1570 else if( pFrame->maRestorePosSize.IsEmpty() )
1571 {
1572 const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
1573 pFrame->maRestorePosSize =
1574 tools::Rectangle( Point( rGeom.nX, rGeom.nY ), Size( rGeom.nWidth, rGeom.nHeight ) );
1575 }
1576 }
1577 else
1578 WMAdaptor::maximizeFrame( pFrame, bHorizontal, bVertical );
1579 }
1580
1581 /*
1582 * GnomeWMAdaptor::maximizeFrame
1583 * changes _WIN_STATE by sending a client message
1584 */
1585
maximizeFrame(X11SalFrame * pFrame,bool bHorizontal,bool bVertical) const1586 void GnomeWMAdaptor::maximizeFrame( X11SalFrame* pFrame, bool bHorizontal, bool bVertical ) const
1587 {
1588 pFrame->mbMaximizedVert = bVertical;
1589 pFrame->mbMaximizedHorz = bHorizontal;
1590
1591 if( m_aWMAtoms[ WIN_STATE ]
1592 && ( pFrame->nStyle_ & ~SalFrameStyleFlags::DEFAULT )
1593 )
1594 {
1595 if( pFrame->bMapped_ )
1596 {
1597 // window already mapped, send WM a message
1598 XEvent aEvent;
1599 aEvent.type = ClientMessage;
1600 aEvent.xclient.display = m_pDisplay;
1601 aEvent.xclient.window = pFrame->GetShellWindow();
1602 aEvent.xclient.message_type = m_aWMAtoms[ WIN_STATE ];
1603 aEvent.xclient.format = 32;
1604 aEvent.xclient.data.l[0] = (1<<2)|(1<<3);
1605 aEvent.xclient.data.l[1] =
1606 (bVertical ? (1<<2) : 0)
1607 | (bHorizontal ? (1<<3) : 0);
1608 aEvent.xclient.data.l[2] = 0;
1609 aEvent.xclient.data.l[3] = 0;
1610 aEvent.xclient.data.l[4] = 0;
1611 XSendEvent( m_pDisplay,
1612 m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
1613 False,
1614 SubstructureNotifyMask,
1615 &aEvent
1616 );
1617 }
1618 else
1619 // window not mapped yet, set _WIN_STATE directly
1620 setGnomeWMState( pFrame );
1621
1622 if( !bHorizontal && !bVertical )
1623 pFrame->maRestorePosSize = tools::Rectangle();
1624 else if( pFrame->maRestorePosSize.IsEmpty() )
1625 {
1626 const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
1627 pFrame->maRestorePosSize =
1628 tools::Rectangle( Point( rGeom.nX, rGeom.nY ), Size( rGeom.nWidth, rGeom.nHeight ) );
1629 }
1630 }
1631 else
1632 WMAdaptor::maximizeFrame( pFrame, bHorizontal, bVertical );
1633 }
1634
1635 /*
1636 * WMAdaptor::enableAlwaysOnTop
1637 */
enableAlwaysOnTop(X11SalFrame *,bool) const1638 void WMAdaptor::enableAlwaysOnTop( X11SalFrame*, bool /*bEnable*/ ) const
1639 {
1640 }
1641
1642 /*
1643 * NetWMAdaptor::enableAlwaysOnTop
1644 */
enableAlwaysOnTop(X11SalFrame * pFrame,bool bEnable) const1645 void NetWMAdaptor::enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const
1646 {
1647 pFrame->bAlwaysOnTop_ = bEnable;
1648 if( m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ] )
1649 {
1650 if( pFrame->bMapped_ )
1651 {
1652 // window already mapped, send WM a message
1653 XEvent aEvent;
1654 aEvent.type = ClientMessage;
1655 aEvent.xclient.display = m_pDisplay;
1656 aEvent.xclient.window = pFrame->GetShellWindow();
1657 aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ];
1658 aEvent.xclient.format = 32;
1659 aEvent.xclient.data.l[0] = bEnable ? 1 : 0;
1660 aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ];
1661 aEvent.xclient.data.l[2] = 0;
1662 aEvent.xclient.data.l[3] = 0;
1663 aEvent.xclient.data.l[4] = 0;
1664 XSendEvent( m_pDisplay,
1665 m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
1666 False,
1667 SubstructureNotifyMask | SubstructureRedirectMask,
1668 &aEvent
1669 );
1670 }
1671 else
1672 setNetWMState( pFrame );
1673 }
1674 }
1675
1676 /*
1677 * GnomeWMAdaptor::enableAlwaysOnTop
1678 */
enableAlwaysOnTop(X11SalFrame * pFrame,bool bEnable) const1679 void GnomeWMAdaptor::enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const
1680 {
1681 pFrame->bAlwaysOnTop_ = bEnable;
1682 if( m_aWMAtoms[ WIN_LAYER ] )
1683 {
1684 if( pFrame->bMapped_ )
1685 {
1686 // window already mapped, send WM a message
1687 XEvent aEvent;
1688 aEvent.type = ClientMessage;
1689 aEvent.xclient.display = m_pDisplay;
1690 aEvent.xclient.window = pFrame->GetShellWindow();
1691 aEvent.xclient.message_type = m_aWMAtoms[ WIN_LAYER ];
1692 aEvent.xclient.format = 32;
1693 aEvent.xclient.data.l[0] = bEnable ? 6 : 4;
1694 aEvent.xclient.data.l[1] = 0;
1695 aEvent.xclient.data.l[2] = 0;
1696 aEvent.xclient.data.l[3] = 0;
1697 aEvent.xclient.data.l[4] = 0;
1698 XSendEvent( m_pDisplay,
1699 m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
1700 False,
1701 SubstructureNotifyMask | SubstructureRedirectMask,
1702 &aEvent
1703 );
1704 }
1705 else
1706 {
1707 sal_uInt32 nNewLayer = bEnable ? 6 : 4;
1708 XChangeProperty( m_pDisplay,
1709 pFrame->GetShellWindow(),
1710 m_aWMAtoms[ WIN_LAYER ],
1711 XA_CARDINAL,
1712 32,
1713 PropModeReplace,
1714 reinterpret_cast<unsigned char*>(&nNewLayer),
1715 1
1716 );
1717 }
1718 }
1719 }
1720
1721 /*
1722 * WMAdaptor::changeReferenceFrame
1723 */
changeReferenceFrame(X11SalFrame * pFrame,X11SalFrame const * pReferenceFrame) const1724 void WMAdaptor::changeReferenceFrame( X11SalFrame* pFrame, X11SalFrame const * pReferenceFrame ) const
1725 {
1726 if( ! ( pFrame->nStyle_ & SalFrameStyleFlags::PLUG )
1727 && ! pFrame->IsOverrideRedirect()
1728 && ! pFrame->IsFloatGrabWindow()
1729 )
1730 {
1731 ::Window aTransient = pFrame->pDisplay_->GetRootWindow( pFrame->GetScreenNumber() );
1732 pFrame->mbTransientForRoot = true;
1733 if( pReferenceFrame )
1734 {
1735 aTransient = pReferenceFrame->GetShellWindow();
1736 pFrame->mbTransientForRoot = false;
1737 }
1738 XSetTransientForHint( m_pDisplay,
1739 pFrame->GetShellWindow(),
1740 aTransient );
1741 }
1742 }
1743
1744 /*
1745 * WMAdaptor::handlePropertyNotify
1746 */
handlePropertyNotify(X11SalFrame *,XPropertyEvent *) const1747 int WMAdaptor::handlePropertyNotify( X11SalFrame*, XPropertyEvent* ) const
1748 {
1749 return 0;
1750 }
1751
1752 /*
1753 * NetWMAdaptor::handlePropertyNotify
1754 */
handlePropertyNotify(X11SalFrame * pFrame,XPropertyEvent * pEvent) const1755 int NetWMAdaptor::handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const
1756 {
1757 int nHandled = 1;
1758 if( pEvent->atom == m_aWMAtoms[ NET_WM_STATE ] )
1759 {
1760 pFrame->mbMaximizedHorz = pFrame->mbMaximizedVert = false;
1761 pFrame->mbShaded = false;
1762
1763 if( pEvent->state == PropertyNewValue )
1764 {
1765 Atom nType, *pStates;
1766 int nFormat;
1767 unsigned long nItems, nBytesLeft;
1768 unsigned char* pData = nullptr;
1769 long nOffset = 0;
1770 do
1771 {
1772 XGetWindowProperty( m_pDisplay,
1773 pEvent->window,
1774 m_aWMAtoms[ NET_WM_STATE ],
1775 nOffset, 64,
1776 False,
1777 XA_ATOM,
1778 &nType,
1779 &nFormat,
1780 &nItems, &nBytesLeft,
1781 &pData );
1782 if( pData )
1783 {
1784 if( nType == XA_ATOM && nFormat == 32 && nItems > 0 )
1785 {
1786 pStates = reinterpret_cast<Atom*>(pData);
1787 for( unsigned long i = 0; i < nItems; i++ )
1788 {
1789 if( pStates[i] == m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] )
1790 pFrame->mbMaximizedVert = true;
1791 else if( pStates[i] == m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ] && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ] )
1792 pFrame->mbMaximizedHorz = true;
1793 else if( pStates[i] == m_aWMAtoms[ NET_WM_STATE_SHADED ] && m_aWMAtoms[ NET_WM_STATE_SHADED ] )
1794 pFrame->mbShaded = true;
1795 }
1796 }
1797 XFree( pData );
1798 pData = nullptr;
1799 nOffset += nItems * nFormat / 32;
1800 }
1801 else
1802 break;
1803 } while( nBytesLeft > 0 );
1804 }
1805
1806 if( ! (pFrame->mbMaximizedHorz || pFrame->mbMaximizedVert ) )
1807 pFrame->maRestorePosSize = tools::Rectangle();
1808 else
1809 {
1810 const SalFrameGeometry& rGeom = pFrame->GetUnmirroredGeometry();
1811 // the current geometry may already be changed by the corresponding
1812 // ConfigureNotify, but this cannot be helped
1813 pFrame->maRestorePosSize =
1814 tools::Rectangle( Point( rGeom.nX, rGeom.nY ),
1815 Size( rGeom.nWidth, rGeom.nHeight ) );
1816 }
1817 }
1818 else if( pEvent->atom == m_aWMAtoms[ NET_WM_DESKTOP ] )
1819 {
1820 pFrame->m_nWorkArea = getWindowWorkArea( pFrame->GetShellWindow() );
1821 }
1822 else
1823 nHandled = 0;
1824
1825 return nHandled;
1826 }
1827
1828 /*
1829 * GnomeWMAdaptor::handlePropertyNotify
1830 */
handlePropertyNotify(X11SalFrame * pFrame,XPropertyEvent * pEvent) const1831 int GnomeWMAdaptor::handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const
1832 {
1833 int nHandled = 1;
1834 if( pEvent->atom == m_aWMAtoms[ WIN_STATE ] )
1835 {
1836 pFrame->mbMaximizedHorz = pFrame->mbMaximizedVert = false;
1837 pFrame->mbShaded = false;
1838
1839 if( pEvent->state == PropertyNewValue )
1840 {
1841 Atom nType;
1842 int nFormat = 0;
1843 unsigned long nItems = 0;
1844 unsigned long nBytesLeft = 0;
1845 unsigned char* pData = nullptr;
1846 XGetWindowProperty( m_pDisplay,
1847 pEvent->window,
1848 m_aWMAtoms[ WIN_STATE ],
1849 0, 1,
1850 False,
1851 XA_CARDINAL,
1852 &nType,
1853 &nFormat,
1854 &nItems, &nBytesLeft,
1855 &pData );
1856 if( pData )
1857 {
1858 if( nType == XA_CARDINAL && nFormat == 32 && nItems == 1 )
1859 {
1860 sal_uInt32 nWinState = *reinterpret_cast<sal_uInt32*>(pData);
1861 if( nWinState & (1<<2) )
1862 pFrame->mbMaximizedVert = true;
1863 if( nWinState & (1<<3) )
1864 pFrame->mbMaximizedHorz = true;
1865 if( nWinState & (1<<5) )
1866 pFrame->mbShaded = true;
1867 }
1868 XFree( pData );
1869 }
1870 }
1871
1872 if( ! (pFrame->mbMaximizedHorz || pFrame->mbMaximizedVert ) )
1873 pFrame->maRestorePosSize = tools::Rectangle();
1874 else
1875 {
1876 const SalFrameGeometry& rGeom = pFrame->GetUnmirroredGeometry();
1877 // the current geometry may already be changed by the corresponding
1878 // ConfigureNotify, but this cannot be helped
1879 pFrame->maRestorePosSize =
1880 tools::Rectangle( Point( rGeom.nX, rGeom.nY ),
1881 Size( rGeom.nWidth, rGeom.nHeight ) );
1882 }
1883 }
1884 else if( pEvent->atom == m_aWMAtoms[ NET_WM_DESKTOP ] )
1885 {
1886 pFrame->m_nWorkArea = getWindowWorkArea( pFrame->GetShellWindow() );
1887 }
1888 else
1889 nHandled = 0;
1890
1891 return nHandled;
1892 }
1893
1894 /*
1895 * WMAdaptor::shade
1896 */
shade(X11SalFrame *,bool) const1897 void WMAdaptor::shade( X11SalFrame*, bool /*bToShaded*/ ) const
1898 {
1899 }
1900
1901 /*
1902 * NetWMAdaptor::shade
1903 */
shade(X11SalFrame * pFrame,bool bToShaded) const1904 void NetWMAdaptor::shade( X11SalFrame* pFrame, bool bToShaded ) const
1905 {
1906 if( m_aWMAtoms[ NET_WM_STATE ]
1907 && m_aWMAtoms[ NET_WM_STATE_SHADED ]
1908 && ( pFrame->nStyle_ & ~SalFrameStyleFlags::DEFAULT )
1909 )
1910 {
1911 pFrame->mbShaded = bToShaded;
1912 if( pFrame->bMapped_ )
1913 {
1914 // window already mapped, send WM a message
1915 XEvent aEvent;
1916 aEvent.type = ClientMessage;
1917 aEvent.xclient.display = m_pDisplay;
1918 aEvent.xclient.window = pFrame->GetShellWindow();
1919 aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ];
1920 aEvent.xclient.format = 32;
1921 aEvent.xclient.data.l[0] = bToShaded ? 1 : 0;
1922 aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_SHADED ];
1923 aEvent.xclient.data.l[2] = 0;
1924 aEvent.xclient.data.l[3] = 0;
1925 aEvent.xclient.data.l[4] = 0;
1926 XSendEvent( m_pDisplay,
1927 m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
1928 False,
1929 SubstructureNotifyMask | SubstructureRedirectMask,
1930 &aEvent
1931 );
1932 }
1933 else
1934 {
1935 // window not mapped yet, set _NET_WM_STATE directly
1936 setNetWMState( pFrame );
1937 }
1938 }
1939 }
1940
1941 /*
1942 * GnomeWMAdaptor::shade
1943 */
shade(X11SalFrame * pFrame,bool bToShaded) const1944 void GnomeWMAdaptor::shade( X11SalFrame* pFrame, bool bToShaded ) const
1945 {
1946 if( m_aWMAtoms[ WIN_STATE ] )
1947 {
1948 pFrame->mbShaded = bToShaded;
1949 if( pFrame->bMapped_ )
1950 {
1951 // window already mapped, send WM a message
1952 XEvent aEvent;
1953 aEvent.type = ClientMessage;
1954 aEvent.xclient.display = m_pDisplay;
1955 aEvent.xclient.window = pFrame->GetShellWindow();
1956 aEvent.xclient.message_type = m_aWMAtoms[ WIN_STATE ];
1957 aEvent.xclient.format = 32;
1958 aEvent.xclient.data.l[0] = (1<<5);
1959 aEvent.xclient.data.l[1] = bToShaded ? (1<<5) : 0;
1960 aEvent.xclient.data.l[2] = 0;
1961 aEvent.xclient.data.l[3] = 0;
1962 aEvent.xclient.data.l[4] = 0;
1963 XSendEvent( m_pDisplay,
1964 m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
1965 False,
1966 SubstructureNotifyMask | SubstructureRedirectMask,
1967 &aEvent
1968 );
1969 }
1970 else
1971 setGnomeWMState( pFrame );
1972 }
1973 }
1974
1975 /*
1976 * WMAdaptor::showFullScreen
1977 */
showFullScreen(X11SalFrame * pFrame,bool bFullScreen) const1978 void WMAdaptor::showFullScreen( X11SalFrame* pFrame, bool bFullScreen ) const
1979 {
1980 pFrame->mbFullScreen = bFullScreen;
1981 maximizeFrame( pFrame, bFullScreen, bFullScreen );
1982 }
1983
1984 /*
1985 * NetWMAdaptor::showFullScreen
1986 */
showFullScreen(X11SalFrame * pFrame,bool bFullScreen) const1987 void NetWMAdaptor::showFullScreen( X11SalFrame* pFrame, bool bFullScreen ) const
1988 {
1989 if( m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ] )
1990 {
1991 pFrame->mbFullScreen = bFullScreen;
1992 if( bFullScreen )
1993 {
1994 if( m_aWMAtoms[ MOTIF_WM_HINTS ] )
1995 {
1996 XDeleteProperty( m_pDisplay,
1997 pFrame->GetShellWindow(),
1998 m_aWMAtoms[ MOTIF_WM_HINTS ] );
1999 }
2000 }
2001 if( pFrame->bMapped_ )
2002 {
2003 // window already mapped, send WM a message
2004 XEvent aEvent;
2005 aEvent.type = ClientMessage;
2006 aEvent.xclient.display = m_pDisplay;
2007 aEvent.xclient.window = pFrame->GetShellWindow();
2008 aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ];
2009 aEvent.xclient.format = 32;
2010 aEvent.xclient.data.l[0] = bFullScreen ? 1 : 0;
2011 aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ];
2012 aEvent.xclient.data.l[2] = 0;
2013 aEvent.xclient.data.l[3] = 0;
2014 aEvent.xclient.data.l[4] = 0;
2015 XSendEvent( m_pDisplay,
2016 m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
2017 False,
2018 SubstructureNotifyMask | SubstructureRedirectMask,
2019 &aEvent
2020 );
2021 }
2022 else
2023 {
2024 // window not mapped yet, set _NET_WM_STATE directly
2025 setNetWMState( pFrame );
2026 }
2027 // #i42750# guess size before resize event shows up
2028 if( bFullScreen )
2029 {
2030 if( m_pSalDisplay->IsXinerama() )
2031 {
2032 ::Window aRoot, aChild;
2033 int root_x = 0, root_y = 0, lx, ly;
2034 unsigned int mask;
2035 XQueryPointer( m_pDisplay,
2036 m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
2037 &aRoot, &aChild,
2038 &root_x, &root_y, &lx, &ly, &mask );
2039 const std::vector< tools::Rectangle >& rScreens = m_pSalDisplay->GetXineramaScreens();
2040 Point aMousePoint( root_x, root_y );
2041 for(const auto & rScreen : rScreens)
2042 {
2043 if( rScreen.IsInside( aMousePoint ) )
2044 {
2045 pFrame->maGeometry.nX = rScreen.Left();
2046 pFrame->maGeometry.nY = rScreen.Top();
2047 pFrame->maGeometry.nWidth = rScreen.GetWidth();
2048 pFrame->maGeometry.nHeight = rScreen.GetHeight();
2049 break;
2050 }
2051 }
2052 }
2053 else
2054 {
2055 Size aSize = m_pSalDisplay->GetScreenSize( pFrame->GetScreenNumber() );
2056 pFrame->maGeometry.nX = 0;
2057 pFrame->maGeometry.nY = 0;
2058 pFrame->maGeometry.nWidth = aSize.Width();
2059 pFrame->maGeometry.nHeight = aSize.Height();
2060 }
2061 pFrame->CallCallback( SalEvent::MoveResize, nullptr );
2062 }
2063 }
2064 else WMAdaptor::showFullScreen( pFrame, bFullScreen );
2065 }
2066
2067 /*
2068 * WMAdaptor::getCurrentWorkArea
2069 */
2070 // FIXME: multiscreen case
getCurrentWorkArea() const2071 int WMAdaptor::getCurrentWorkArea() const
2072 {
2073 int nCurrent = -1;
2074 if( m_aWMAtoms[ NET_CURRENT_DESKTOP ] )
2075 {
2076 Atom aRealType = None;
2077 int nFormat = 8;
2078 unsigned long nItems = 0;
2079 unsigned long nBytesLeft = 0;
2080 unsigned char* pProperty = nullptr;
2081 if( XGetWindowProperty( m_pDisplay,
2082 m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ),
2083 m_aWMAtoms[ NET_CURRENT_DESKTOP ],
2084 0, 1,
2085 False,
2086 XA_CARDINAL,
2087 &aRealType,
2088 &nFormat,
2089 &nItems,
2090 &nBytesLeft,
2091 &pProperty ) == 0
2092 && pProperty
2093 )
2094 {
2095 nCurrent = int(*reinterpret_cast<sal_Int32*>(pProperty));
2096 XFree( pProperty );
2097 }
2098 else if( pProperty )
2099 {
2100 XFree( pProperty );
2101 pProperty = nullptr;
2102 }
2103 }
2104 return nCurrent;
2105 }
2106
2107 /*
2108 * WMAdaptor::getWindowWorkArea
2109 */
getWindowWorkArea(::Window aWindow) const2110 int WMAdaptor::getWindowWorkArea( ::Window aWindow ) const
2111 {
2112 int nCurrent = -1;
2113 if( m_aWMAtoms[ NET_WM_DESKTOP ] )
2114 {
2115 Atom aRealType = None;
2116 int nFormat = 8;
2117 unsigned long nItems = 0;
2118 unsigned long nBytesLeft = 0;
2119 unsigned char* pProperty = nullptr;
2120 if( XGetWindowProperty( m_pDisplay,
2121 aWindow,
2122 m_aWMAtoms[ NET_WM_DESKTOP ],
2123 0, 1,
2124 False,
2125 XA_CARDINAL,
2126 &aRealType,
2127 &nFormat,
2128 &nItems,
2129 &nBytesLeft,
2130 &pProperty ) == 0
2131 && pProperty
2132 )
2133 {
2134 nCurrent = int(*reinterpret_cast<sal_Int32*>(pProperty));
2135 XFree( pProperty );
2136 }
2137 else if( pProperty )
2138 {
2139 XFree( pProperty );
2140 pProperty = nullptr;
2141 }
2142 }
2143 return nCurrent;
2144 }
2145
2146 /*
2147 * WMAdaptor::getCurrentWorkArea
2148 */
2149 // fixme: multi screen case
switchToWorkArea(int nWorkArea) const2150 void WMAdaptor::switchToWorkArea( int nWorkArea ) const
2151 {
2152 if( ! getWMshouldSwitchWorkspace() )
2153 return;
2154
2155 if( !m_aWMAtoms[ NET_CURRENT_DESKTOP ] )
2156 return;
2157
2158 XEvent aEvent;
2159 aEvent.type = ClientMessage;
2160 aEvent.xclient.display = m_pDisplay;
2161 aEvent.xclient.window = m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() );
2162 aEvent.xclient.message_type = m_aWMAtoms[ NET_CURRENT_DESKTOP ];
2163 aEvent.xclient.format = 32;
2164 aEvent.xclient.data.l[0] = nWorkArea;
2165 aEvent.xclient.data.l[1] = 0;
2166 aEvent.xclient.data.l[2] = 0;
2167 aEvent.xclient.data.l[3] = 0;
2168 aEvent.xclient.data.l[4] = 0;
2169 XSendEvent( m_pDisplay,
2170 m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ),
2171 False,
2172 SubstructureNotifyMask | SubstructureRedirectMask,
2173 &aEvent
2174 );
2175
2176 }
2177
2178 /*
2179 * WMAdaptor::frameIsMapping
2180 */
frameIsMapping(X11SalFrame *) const2181 void WMAdaptor::frameIsMapping( X11SalFrame* ) const
2182 {
2183 }
2184
2185 /*
2186 * NetWMAdaptor::frameIsMapping
2187 */
frameIsMapping(X11SalFrame * pFrame) const2188 void NetWMAdaptor::frameIsMapping( X11SalFrame* pFrame ) const
2189 {
2190 setNetWMState( pFrame );
2191 }
2192
2193 /*
2194 * WMAdaptor::setUserTime
2195 */
setUserTime(X11SalFrame *,long) const2196 void WMAdaptor::setUserTime( X11SalFrame*, long ) const
2197 {
2198 }
2199
2200 /*
2201 * NetWMAdaptor::setUserTime
2202 */
setUserTime(X11SalFrame * i_pFrame,long i_nUserTime) const2203 void NetWMAdaptor::setUserTime( X11SalFrame* i_pFrame, long i_nUserTime ) const
2204 {
2205 if( m_aWMAtoms[NET_WM_USER_TIME] )
2206 {
2207 XChangeProperty( m_pDisplay,
2208 i_pFrame->GetShellWindow(),
2209 m_aWMAtoms[NET_WM_USER_TIME],
2210 XA_CARDINAL,
2211 32,
2212 PropModeReplace,
2213 reinterpret_cast<unsigned char*>(&i_nUserTime),
2214 1
2215 );
2216 }
2217 }
2218
2219 /*
2220 * WMAdaptor::setPID
2221 */
setPID(X11SalFrame const * i_pFrame) const2222 void WMAdaptor::setPID( X11SalFrame const * i_pFrame ) const
2223 {
2224 if( m_aWMAtoms[NET_WM_PID] )
2225 {
2226 long nPID = static_cast<long>(getpid());
2227 XChangeProperty( m_pDisplay,
2228 i_pFrame->GetShellWindow(),
2229 m_aWMAtoms[NET_WM_PID],
2230 XA_CARDINAL,
2231 32,
2232 PropModeReplace,
2233 reinterpret_cast<unsigned char*>(&nPID),
2234 1
2235 );
2236 }
2237 }
2238
2239 /*
2240 * WMAdaptor::setClientMachine
2241 */
setClientMachine(X11SalFrame const * i_pFrame) const2242 void WMAdaptor::setClientMachine( X11SalFrame const * i_pFrame ) const
2243 {
2244 OString aWmClient( OUStringToOString( GetGenericUnixSalData()->GetHostname(), RTL_TEXTENCODING_ASCII_US ) );
2245 XTextProperty aClientProp = { reinterpret_cast<unsigned char *>(const_cast<char *>(aWmClient.getStr())), XA_STRING, 8, sal::static_int_cast<unsigned long>( aWmClient.getLength() ) };
2246 XSetWMClientMachine( m_pDisplay, i_pFrame->GetShellWindow(), &aClientProp );
2247 }
2248
answerPing(X11SalFrame const * i_pFrame,XClientMessageEvent const * i_pEvent) const2249 void WMAdaptor::answerPing( X11SalFrame const * i_pFrame, XClientMessageEvent const * i_pEvent ) const
2250 {
2251 if( m_aWMAtoms[NET_WM_PING] &&
2252 i_pEvent->message_type == m_aWMAtoms[ WM_PROTOCOLS ] &&
2253 static_cast<Atom>(i_pEvent->data.l[0]) == m_aWMAtoms[ NET_WM_PING ] )
2254 {
2255 XEvent aEvent;
2256 aEvent.xclient = *i_pEvent;
2257 aEvent.xclient.window = m_pSalDisplay->GetRootWindow( i_pFrame->GetScreenNumber() );
2258 XSendEvent( m_pDisplay,
2259 m_pSalDisplay->GetRootWindow( i_pFrame->GetScreenNumber() ),
2260 False,
2261 SubstructureNotifyMask | SubstructureRedirectMask,
2262 &aEvent
2263 );
2264 XFlush( m_pDisplay );
2265 }
2266 }
2267
activateWindow(X11SalFrame const * pFrame,Time nTimestamp)2268 void WMAdaptor::activateWindow( X11SalFrame const *pFrame, Time nTimestamp )
2269 {
2270 if (!pFrame->bMapped_)
2271 return;
2272
2273 XEvent aEvent;
2274
2275 aEvent.xclient.type = ClientMessage;
2276 aEvent.xclient.window = pFrame->GetShellWindow();
2277 aEvent.xclient.message_type = m_aWMAtoms[ NET_ACTIVE_WINDOW ];
2278 aEvent.xclient.format = 32;
2279 aEvent.xclient.data.l[0] = 1;
2280 aEvent.xclient.data.l[1] = nTimestamp;
2281 aEvent.xclient.data.l[2] = None;
2282 aEvent.xclient.data.l[3] = 0;
2283 aEvent.xclient.data.l[4] = 0;
2284
2285 XSendEvent( m_pDisplay,
2286 m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
2287 False,
2288 SubstructureNotifyMask | SubstructureRedirectMask,
2289 &aEvent );
2290
2291 }
2292
2293 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2294